Upload
ider-zheng
View
923
Download
2
Embed Size (px)
DESCRIPTION
Loc (Lua to Objective-C) is a bridge of type conversion between Lua and Objective-C. This presentation shows the design idea of Loc.
Citation preview
Introduction to Loc A bridge between Lua and Objective-C
Data Type Mapping
Lua Type Objective-C Type
LUA_TNIL nil
LUA_TBOOLEAN BOOL (? NSNumber)
LUA_TLIGHTUSERDATA
LUA_TNUMBER NSNumber
LUA_TSTRING NSString
LUA_TTABLE NS(Mutable)Dictionary (? NSArray)
LUA_TFUNCTION C Function Pointer (Lua Function)
LUA_TUSERDATA
(?) NSObject
Table Lua Table type implements associative arrays.
It can be used as Array with numeric index:
local array = {0,1, "string3", true};
or Dictionary with string key:
local dict = {"hello"="world", 8="storm"};!
Pound(#) operator would return the length of table if table is Array, but it does not count string key/value pairs.
print(#array); 4
Metatable
Metatable is still a table.
It is attached to other Lua type to:
Ø Identify a value as a “Class”
Ø Provide default behaviors by Metamethods
Set/Get Metatable
• Lua API
getmetatable (object)!
setmetatable (table, metatable)!
!(In Lua, only able to set metatable on table)!
• C API
int lua_setmetatable (lua_State *L, int objindex)!
int lua_getmetatable (lua_State *L, int objindex)
Metamethod
Simple explain: they are a set of special keys in metatable.
The values assigned with those keys will automatically trigger in certain situation.
Technical explain: they are Operator Overloading
__add, __sub, __mul, __div, __mod, __pow, __unm, __concat, __len, __eq, __lt, __le, __index, __newindex, __call
__index
Trigger
• Try to get value from key which does not exist in original table
Metametahod Value
• A function • A Table
Effect
• Call __index(table, key) • Return __index[key]
__newindex
Trigger
• Try to set value to key which does not exist in original table
Metametahod Value
• A function • A Table
Effect
• Call __newindex(table, key, value) • __newindex[key] = value;
__call
Trigger • Use table as function, and call with ()
Metametahod Value
• A function
Effect • Call __call(table, …); … are arguments
Colon(:) vs Dot(.)
Lua is not Class based Object oriented language, this or self is not reserved keyword. When call a method on object(table), inside method it don’t know which object it is using. Programmer has to manually pass it to method:
obj.count(obj);!
When define the method, we also need to reserve a argument for it, and we could define the argument name as this or self.
function count(self) {!
return #self;!
}!
Colon(:) vs Dot(.)
Lua provide a syntax sugar, we could use colon(:) to call method, and it will automatically pass the caller as first argument.
obj:count();
However, when define the method, we still need to reserve first position of argument for caller.
Userdata
The userdata type allows arbitrary C data to be stored in Lua variables.
void *lua_newuserdata (lua_State *L, size_t size)
It allocate memory with given size, and return pointer to that memory address.
It’s very similar to C void *malloc(size_t); except with above API, the memory is allocated in Lua, hence Lua GC will automatically free it, if there is no reference on it.
Metatable on Userdata
Lua has not predefined any operations for Userdata, except assignment and equality test.
Userdata does not contain any key, hence any get/set of key would always trigger metamethod. Developer could define a custom metatable and set to userdata to provide certain functionalities.
E.g.: when set value on key, with __newindex we could redirect to set value on relative property; when compare two user data, with __eq we could compare not only the address but also the content.
Light Userdata
A light userdata is a value that represents a C pointer (i.e. a void * value).
void lua_pushlightuserdata (lua_State *L, void *p)
Lua only hold the pointer to a memory, the program out of Lua should handle the memory manager of that data.
Light Userdata vs Userdata
All the light userdata share the same metatable. Push A to Lua as light userdata;
Set MTX on A as metatable;
Push B to Lua as light userdata;
Get metatable of B, you will get MTX, not nil;
Set MTY on B as metatable;
Metatable of A will also change to MTY
Userdata has it’s own metatable, and programmer need to set metatable on each new created userdata
Loc Design
1. Create metatable, bind C functions to metamethods
2. Create userdata, set the address of object to it
3. Set metatable on userdata
4. Push userdata to lua
Whenever we need to push objective-C object to Lua, we do step 2-4
Use Light Userdata
" pushid
lua_pushlightuserdata(L, self);!
luaL_getmetatable(L, name);
lua_setmetatable(L, -2);
" toid
return (id)lua_touserdata(L, idx);
Use Userdata
" pushid
id *ud = (id*)lua_newuserdata(L, sizeof(id));!
*ud = self;!
luaL_getmetatable(L, name);
lua_setmetatable(L, -2);
" toid
return *((id*)lua_touserdata(L, idx));
Loc Trigger on Setter
Lua statement
• object.propertyName = value;
Trigger __newIndex
• __newindex(object, propertyName, value);
Call to bond C Function
• Retrieve userdata back to Object, get other info
Call Objective-C
• [object setValue:value forKey:propertyName];
Loc Trigger on Getter
Object has data members, and method members.
When using Lua syntax to request member with name, inside __index method, only the name is provided, we don’t know the result should be a value, or a function which would accept more arguments. Because we don’t know if there are parenthesis after the name or not.
So in __index, Loc always return a function (use table with __call metamethod to implement a functor). Later call on that function, if there is no argument, we treat as property.
Loc Trigger on Method Call
Lua statement
• value = object:propertyName(); • result = object:methodName(arguments);
Trigger __newIndex
• Create new table; save Name in table; set metatable
Trigger __call • Retrieve object; get name from table; parse arugments
Trigger __call
• [object valueForKey:propertyName]; • Use NSInvocaton to reflect the method call
Loc Function Call Process
object:methodName(arguments);!
__index(object, methodName)!
functor = { _key = methodName };!
setMetatable(functor)!
return functor;!
Loc Function Call Process
object:functor(arguments);!
functor(object, arguments)!
__call(functor, object, arguments)!
methodName = functor[_key];!
selector = convert(methodName);!
invocation = NSInvocatoin(...);!
invocation.invoke();!
return invocation.result;!
NSDictionary & NSArray
NSDictionary and NSArray are well-defined system class. The functionalities required are more clear than user defined classes. So we don’t need to use reflection for them.
Loc define C functions to directly map to relative instance methods.
This is done by setting table, which contains a set of C Functions, on __index of metatable, and called by colon(:) syntax.
LocDictionary
Selector Functions __index
Table
get(k) objectForKey:
set(k,v) setObject:forKey:
count() count
… …
Some methods may would allowed for NSMutableDictionary
LocArray
Selector Functions __index
Table
get(i) objectAtIndex:
add(o) addObject:
count() count
… …
Some methods may would allowed for NSMutableArray The index is 1-based, it will convert to 0-based in methods
LocLuaLib " It is a set of utility methods as Lua Library.
" It register as global table loc.
Method Library loc
loc
toclass(str) NSClassFromString()
todictionary(t) loc_todictionary()
toarray(t) loc_toarray()
Q & A
You may also like to know
Registry: http://www.lua.org/pil/27.3.1.html Special place to share global data between C functions
Privacy: http://www.lua.org/pil/15.2.html Use local table as key for other table
Metatable protection: http://www.lua.org/pil/13.3.html __metatable
C Library: http://www.lua.org/pil/26.2.html Register a set of C Functions as Lua Library