Browse Source

support for calling js functions by name rather than through 'nodelua'

v0.2.x
Brett Langdon 13 years ago
parent
commit
3dae8a5b62
2 changed files with 260 additions and 19 deletions
  1. +244
    -18
      src/luastate.cc
  2. +16
    -1
      src/luastate.h

+ 244
- 18
src/luastate.cc View File

@ -4,24 +4,38 @@
using namespace v8;
uv_async_t async;
std::map<char*, Persistent<Function> > functions;
struct async_baton{
bool has_cb;
Persistent<Function> callback;
char* name;
char* data;
bool error;
char msg[1000];
LuaState* state;
};
void do_file(uv_work_t *req){
async_baton* baton = static_cast<async_baton*>(req->data);
if(luaL_dofile(baton->state->lua_, baton->name)){
if(luaL_dofile(baton->state->lua_, baton->data)){
baton->error = true;
sprintf(baton->msg, "Exception In File %s Has Failed:\n%s\n", baton->data, lua_tostring(baton->state->lua_, -1));
}
}
void do_string(uv_work_t *req){
async_baton* baton = static_cast<async_baton*>(req->data);
if(luaL_dostring(baton->state->lua_, baton->data)){
baton->error = true;
sprintf(baton->msg, "Exception In File %s Has Failed:\n%s\n", baton->name, lua_tostring(baton->state->lua_, -1));
sprintf(baton->msg, "Exception Of Lua Code Has Failed:\n%s\n", baton->data, lua_tostring(baton->state->lua_, -1));
}
}
void async_after(uv_work_t *req){
HandleScope scope;
@ -44,7 +58,9 @@ void async_after(uv_work_t *req){
TryCatch try_catch;
baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if(baton->has_cb){
baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);
}
baton->callback.Dispose();
delete baton;
@ -55,9 +71,11 @@ void async_after(uv_work_t *req){
}
}
LuaState::LuaState(){};
LuaState::~LuaState(){};
void LuaState::Init(Handle<Object> target){
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(String::NewSymbol("LuaState"));
@ -68,18 +86,64 @@ void LuaState::Init(Handle<Object> target){
tpl->PrototypeTemplate()->Set(String::NewSymbol("doFile"),
FunctionTemplate::New(DoFile)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("doStringSync"),
FunctionTemplate::New(DoStringSync)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("doString"),
FunctionTemplate::New(DoString)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("setGlobal"),
FunctionTemplate::New(SetGlobal)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("getGlobal"),
FunctionTemplate::New(GetGlobal)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("status"),
FunctionTemplate::New(Status)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("close"),
FunctionTemplate::New(Close)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("collectGarbage"),
FunctionTemplate::New(CollectGarbage)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("registerFunction"),
FunctionTemplate::New(RegisterFunction)->GetFunction());
Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
target->Set(String::NewSymbol("LuaState"), constructor);
}
int LuaState::CallFunction(lua_State* L){
int n = lua_gettop(L);
char * func_name = (char *)lua_tostring(L, lua_upvalueindex(1));
const unsigned argc = n;
Local<Value>* argv = new Local<Value>[argc];
int i;
for(i = 1; i <= n; ++i){
argv[i - 1] = lua_to_value(L, i);
}
Handle<Value> ret_val = Undefined();
std::map<char *,Persistent<Function> >::iterator iter;
for(iter = functions.begin(); iter != functions.end(); iter++){
if(strcmp(iter->first, func_name) == 0){
Persistent<Function> func = iter->second;
ret_val = func->Call(Context::GetCurrent()->Global(), argc, argv);
break;
}
}
push_value_to_lua(L, ret_val);
return 1;
}
Handle<Value> LuaState::New(const Arguments& args){
HandleScope scope;
if(!args.IsConstructCall()) {
return ThrowException(Exception::TypeError(String::New("Use the new operator to create instances of this object.")));
return ThrowException(Exception::TypeError(String::New("LuaState Requires The 'new' Operator To Create An Instance")));
}
LuaState* obj = new LuaState();
@ -90,16 +154,17 @@ Handle<Value> LuaState::New(const Arguments& args){
return args.This();
}
Handle<Value> LuaState::DoFileSync(const Arguments& args){
HandleScope scope;
if(args.Length() < 1){
ThrowException(Exception::TypeError(String::New("doFileSync Takes Only 1 Argument")));
ThrowException(Exception::TypeError(String::New("LuaState.doFileSync Takes Only 1 Argument")));
return scope.Close(Undefined());
}
if(!args[0]->IsString()){
ThrowException(Exception::TypeError(String::New("doFileSync Argument 1 Must Be A String")));
ThrowException(Exception::TypeError(String::New("LuaState.doFileSync Argument 1 Must Be A String")));
return scope.Close(Undefined());
}
@ -120,49 +185,117 @@ Handle<Value> LuaState::DoFileSync(const Arguments& args){
}
}
Handle<Value> LuaState::DoFile(const Arguments& args){
HandleScope scope;
if(args.Length() < 1){
ThrowException(Exception::TypeError(String::New("doFile Requires At Least 1 Argument")));
ThrowException(Exception::TypeError(String::New("LuaState.doFile Requires At Least 1 Argument")));
return scope.Close(Undefined());
}
if(!args[0]->IsString()){
ThrowException(Exception::TypeError(String::New("doFile Argument 1 Must Be A String")));
ThrowException(Exception::TypeError(String::New("LuaState.doFile First Argument Must Be A String")));
return scope.Close(Undefined());
}
if(args.Length() > 2 && !args[1]->IsFunction()){
ThrowException(Exception::TypeError(String::New("doFile Argument 2 Must Be A Function")));
if(args.Length() > 1 && !args[1]->IsFunction()){
ThrowException(Exception::TypeError(String::New("LuaState.doFile Second Argument Must Be A Function")));
return scope.Close(Undefined());
}
char* file_name = get_str(args[0]);
Persistent<Function> callback;
LuaState* obj = ObjectWrap::Unwrap<LuaState>(args.This());
async_baton* baton = new async_baton();
baton->data = get_str(args[0]);
baton->state = obj;
obj->Ref();
if(args.Length() > 1){
callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
baton->has_cb = true;
baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
}
uv_work_t *req = new uv_work_t;
req->data = baton;
uv_queue_work(uv_default_loop(), req, do_file, async_after);
return scope.Close(Undefined());
}
Handle<Value> LuaState::DoStringSync(const Arguments& args) {
HandleScope scope;
if(args.Length() < 1){
ThrowException(Exception::TypeError(String::New("LuaState.doStringSync Requires 1 Argument")));
return scope.Close(Undefined());
}
char *lua_code = get_str(args[0]);
LuaState* obj = ObjectWrap::Unwrap<LuaState>(args.This());
if(luaL_dostring(obj->lua_, lua_code)){
char buf[1000];
sprintf(buf, "Execution Of Lua Code Has Failed:\n%s\n", lua_tostring(obj->lua_, -1));
ThrowException(Exception::TypeError(String::New(buf)));
return scope.Close(Undefined());
}
if(lua_gettop(obj->lua_)){
return scope.Close(lua_to_value(obj->lua_, -1));
} else{
return scope.Close(Undefined());
}
}
Handle<Value> LuaState::DoString(const Arguments& args){
HandleScope scope;
if(args.Length() < 1){
ThrowException(Exception::TypeError(String::New("LuaState.doString Requires At Least 1 Argument")));
return scope.Close(Undefined());
}
if(!args[0]->IsString()){
ThrowException(Exception::TypeError(String::New("LuaState.doString: First Argument Must Be A String")));
return scope.Close(Undefined());
}
LuaState* obj = ObjectWrap::Unwrap<LuaState>(args.This());
async_baton* baton = new async_baton();
baton->name = file_name;
baton->callback = callback;
baton->data = get_str(args[0]);
baton->state = obj;
obj->Ref();
if(args.Length() > 1 && !args[1]->IsFunction()){
ThrowException(Exception::TypeError(String::New("LuaState.doString Second Argument Must Be A Function")));
return scope.Close(Undefined());
}
if(args.Length() > 1){
baton->has_cb = true;
baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
}
uv_work_t *req = new uv_work_t;
req->data = baton;
uv_queue_work(uv_default_loop(), req, do_file, async_after);
uv_queue_work(uv_default_loop(), req, do_string, async_after);
return scope.Close(Undefined());
}
Handle<Value> LuaState::SetGlobal(const Arguments& args) {
HandleScope scope;
if(args.Length() < 2){
ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
ThrowException(Exception::TypeError(String::New("LuaState.setGlobal Requires 2 Arguments")));
return scope.Close(Undefined());
}
if(!args[0]->IsString()){
ThrowException(Exception::TypeError(String::New("LuaState.setGlobal Argument 1 Must Be A String")));
return scope.Close(Undefined());
}
@ -175,3 +308,96 @@ Handle<Value> LuaState::SetGlobal(const Arguments& args) {
return scope.Close(Undefined());
}
Handle<Value> LuaState::GetGlobal(const Arguments& args) {
HandleScope scope;
if(args.Length() < 1){
ThrowException(Exception::TypeError(String::New("LuaState.getGlobal Requires 1 Argument")));
return scope.Close(Undefined());
}
if(!args[0]->IsString()){
ThrowException(Exception::TypeError(String::New("LuaState.getGlobal Argument 1 Must Be A String")));
return scope.Close(Undefined());
}
char *global_name = get_str(args[0]);
LuaState* obj = ObjectWrap::Unwrap<LuaState>(args.This());
lua_getglobal(obj->lua_, global_name);
Local<Value> val = lua_to_value(obj->lua_, -1);
return scope.Close(val);
}
Handle<Value> LuaState::Close(const Arguments& args){
HandleScope scope;
LuaState* obj = ObjectWrap::Unwrap<LuaState>(args.This());
lua_close(obj->lua_);
return scope.Close(Undefined());
}
Handle<Value> LuaState::Status(const Arguments& args){
HandleScope scope;
LuaState* obj = ObjectWrap::Unwrap<LuaState>(args.This());
int status = lua_status(obj->lua_);
return scope.Close(Number::New(status));
}
Handle<Value> LuaState::CollectGarbage(const Arguments& args){
HandleScope scope;
if(args.Length() < 1){
ThrowException(Exception::TypeError(String::New("LuaState.collectGarbage Requires 1 Argument")));
return scope.Close(Undefined());
}
if(!args[0]->IsNumber()){
ThrowException(Exception::TypeError(String::New("LuaSatte.collectGarbage Argument 1 Must Be A Number, try nodelua.GC.[TYPE]")));
return scope.Close(Undefined());
}
LuaState* obj = ObjectWrap::Unwrap<LuaState>(args.This());
int type = (int)args[0]->ToNumber()->Value();
int gc = lua_gc(obj->lua_, type, 0);
return scope.Close(Number::New(gc));
}
Handle<Value> LuaState::RegisterFunction(const Arguments& args){
HandleScope scope;
if(args.Length() < 1){
ThrowException(Exception::TypeError(String::New("nodelua.registerFunction Must Have 2 Arguments")));
return scope.Close(Undefined());
}
if(!args[0]->IsString()){
ThrowException(Exception::TypeError(String::New("nodelua.registerFunction Argument 1 Must Be A String")));
return scope.Close(Undefined());
}
if(!args[1]->IsFunction()){
ThrowException(Exception::TypeError(String::New("nodelua.registerFunction Argument 2 Must Be A Function")));
return scope.Close(Undefined());
}
Persistent<Function> func = Persistent<Function>::New(Local<Function>::Cast(args[1]));
char* func_name = get_str(args[0]);
functions[func_name] = func;
LuaState* obj = ObjectWrap::Unwrap<LuaState>(args.This());
lua_pushstring(obj->lua_, func_name);
lua_pushcclosure(obj->lua_, CallFunction, 1);
lua_setglobal(obj->lua_, func_name);
return scope.Close(Undefined());
}

+ 16
- 1
src/luastate.h View File

@ -1,6 +1,7 @@
#ifndef LUASTATE_H
#define LUASTATE_H
#include <map>
#include <node.h>
#include "utils.h"
@ -13,16 +14,30 @@ extern "C"{
class LuaState : public node::ObjectWrap{
public:
static void Init(v8::Handle<v8::Object> target);
lua_State* lua_;
static void Init(v8::Handle<v8::Object> target);
static int CallFunction(lua_State* L);
private:
LuaState();
~LuaState();
static v8::Handle<v8::Value> New(const v8::Arguments& args);
static v8::Handle<v8::Value> Status(const v8::Arguments& args);
static v8::Handle<v8::Value> Close(const v8::Arguments& args);
static v8::Handle<v8::Value> CollectGarbage(const v8::Arguments& args);
static v8::Handle<v8::Value> DoFileSync(const v8::Arguments& args);
static v8::Handle<v8::Value> DoFile(const v8::Arguments& args);
static v8::Handle<v8::Value> DoStringSync(const v8::Arguments& args);
static v8::Handle<v8::Value> DoString(const v8::Arguments& args);
static v8::Handle<v8::Value> SetGlobal(const v8::Arguments& args);
static v8::Handle<v8::Value> GetGlobal(const v8::Arguments& args);
static v8::Handle<v8::Value> RegisterFunction(const v8::Arguments& args);
};
#endif

Loading…
Cancel
Save