I do not love Objective-C. It makes me feel like I'm in the beginning of 90's. Lots of stupid syntax, square brackets everywhere, separate interfaces/implementations,... Okay, I feel you got me.
There are two "official" solutions for people like me: RubyCocoa and PythonCocoa. Hovewer there is a third solution which people rarely think about: Lua (and other embeddable languages).
This solution slightly differs from RubyCocoa/PythonCocoa. Lua is a very lightweight (but powerful) language which depends on C only. You don't need to pull many N-megabyte frameworks and libraries. Lua was created as an embeddable language: you add its interpreter's source code to your project and use is programmatically. Apart of many other things that means that you can use Lua even on the iPhone and no one will ever notice that.
Thanks to Tom McClean, Eric Wing and others, integrating Lua into your project is terrifically easy. Here is a little tutorial (you can download an exemplary project from http://github.com/fourdman/cocolua/tree/master):
- Download lua's source code from lua.org: http://www.lua.org/ftp/lua-5.1.4.tar.gz
- Download LuaCocoa from http://www.assembla.com/spaces/LuaCocoa/trac_mercurial_tool (you'll need mercurial):
hg clone http://hg.assembla.com/LuaCocoa - Add/copy LuaObjCBridge.{h,m} to your project
- Add/copy all Lua interpreter's *.{h,c} from src/ without lua.c and luac.c
- Compile and ensure that there are no errors.
How to use it?
Launching a script
// create an interpreter
lua_State* interpreter = lua_objc_init();
// do stuff: prepare globals, etc
// run a script
luaL_dofile(interpreter, scriptPath);
// get the error status
char *luaError = (char *)lua_tostring(interpreter, -1);
// do stuff again: read globals, etc
// kill the interpreter
lua_close(interpreter);
Reading/writing global variables
There are two options here: property-list compatible values and just id instances.
In case you want to transfer property-list compatible values across the bridge you do as follows:
lua_objc_pushpropertylist(interpreter, value);
lua_setglobal(interpreter, "globalVar");
Shortly saying you put the value on top of Lua interpreter's stack and then assign that value to a global variable. Property-list compatible values (NSNumber, NSString, NSData, NSArray, NSDictionary) are special in that way that they're automatically transformed into appropriate Lua's native types: number, string, string, table, table.
In case you have an arbitrary object, you do as follows:
lua_objc_pushid(interpreter, object);
lua_setglobal(interpreter, "globalVar");
In this case on Lua's side you get a table corresponding to the transfered object. And, for instance, you can do:
globalVar:describe()
Calling Cocoa code from Lua
theClass = objc.class("NSObject");
theInstance = theClass:alloc():init();
For more info please read LuaCocoa's code or Lua's documentation on its C API.
Actually, there is another even more easier way to operate with Lua's interpreter: LuaCore. This framework provides an even more cool interface:
LCLua *lua = [LCLua readyLua];
[lua pushAsLuaString:@"this is the value of s" withName:@"s"];
[lua pushDictionaryAsTable:[NSDictionary dictionary] withName:@"d"];
[lua pushGlobalObject:self withName:@"myObject"];
[lua runBuffer:@"print(s)"];
[lua runBuffer:@"print(myObject:description())"];
Finally, here are some useful links on Lua and embedding it:
- Lua's home page
- Metalua: Lua with metaprogramming (for pervs)
- Original LuaObjCBridge project
- A simple example of how to use LuaObjCBridge, pretty old and without downloadable code. But you can download my implementation.
- ewing's branch of LuaObjCBridge, adds support for Objective-C 2.0 and contains important bug fixes
- Original LuaCore project
- ewing's branch of LuaCore
- Tutorial: "Embedding Lua in C: Using Lua from inside C."
- Tutorial: "Embedding Lua in 5 Minutes" by code monk
Thanks for the write up! FYI, I wrote a brand new, next-generation LuaCocoa bridge. It's actually at the same URL you posted, but I rebooted that repo at one point.
ReplyDeleteMore info can be found here:
http://playcontrol.net/opensource/LuaCocoa/