rlua 1.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.rdoc +167 -0
- data/README.rdoc +97 -0
- data/ext/extconf.rb +10 -0
- data/ext/rlua.c +1239 -0
- data/lib/rlua.rb +82 -0
- metadata +63 -0
data/LICENSE.rdoc
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
.
|
2
|
+
GNU LESSER GENERAL PUBLIC LICENSE
|
3
|
+
Version 3, 29 June 2007
|
4
|
+
|
5
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
6
|
+
Everyone is permitted to copy and distribute verbatim copies
|
7
|
+
of this license document, but changing it is not allowed.
|
8
|
+
|
9
|
+
|
10
|
+
This version of the GNU Lesser General Public License incorporates
|
11
|
+
the terms and conditions of version 3 of the GNU General Public
|
12
|
+
License, supplemented by the additional permissions listed below.
|
13
|
+
|
14
|
+
0. Additional Definitions.
|
15
|
+
|
16
|
+
As used herein, "this License" refers to version 3 of the GNU Lesser
|
17
|
+
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
18
|
+
General Public License.
|
19
|
+
|
20
|
+
"The Library" refers to a covered work governed by this License,
|
21
|
+
other than an Application or a Combined Work as defined below.
|
22
|
+
|
23
|
+
An "Application" is any work that makes use of an interface provided
|
24
|
+
by the Library, but which is not otherwise based on the Library.
|
25
|
+
Defining a subclass of a class defined by the Library is deemed a mode
|
26
|
+
of using an interface provided by the Library.
|
27
|
+
|
28
|
+
A "Combined Work" is a work produced by combining or linking an
|
29
|
+
Application with the Library. The particular version of the Library
|
30
|
+
with which the Combined Work was made is also called the "Linked
|
31
|
+
Version".
|
32
|
+
|
33
|
+
The "Minimal Corresponding Source" for a Combined Work means the
|
34
|
+
Corresponding Source for the Combined Work, excluding any source code
|
35
|
+
for portions of the Combined Work that, considered in isolation, are
|
36
|
+
based on the Application, and not on the Linked Version.
|
37
|
+
|
38
|
+
The "Corresponding Application Code" for a Combined Work means the
|
39
|
+
object code and/or source code for the Application, including any data
|
40
|
+
and utility programs needed for reproducing the Combined Work from the
|
41
|
+
Application, but excluding the System Libraries of the Combined Work.
|
42
|
+
|
43
|
+
1. Exception to Section 3 of the GNU GPL.
|
44
|
+
|
45
|
+
You may convey a covered work under sections 3 and 4 of this License
|
46
|
+
without being bound by section 3 of the GNU GPL.
|
47
|
+
|
48
|
+
2. Conveying Modified Versions.
|
49
|
+
|
50
|
+
If you modify a copy of the Library, and, in your modifications, a
|
51
|
+
facility refers to a function or data to be supplied by an Application
|
52
|
+
that uses the facility (other than as an argument passed when the
|
53
|
+
facility is invoked), then you may convey a copy of the modified
|
54
|
+
version:
|
55
|
+
|
56
|
+
a) under this License, provided that you make a good faith effort to
|
57
|
+
ensure that, in the event an Application does not supply the
|
58
|
+
function or data, the facility still operates, and performs
|
59
|
+
whatever part of its purpose remains meaningful, or
|
60
|
+
|
61
|
+
b) under the GNU GPL, with none of the additional permissions of
|
62
|
+
this License applicable to that copy.
|
63
|
+
|
64
|
+
3. Object Code Incorporating Material from Library Header Files.
|
65
|
+
|
66
|
+
The object code form of an Application may incorporate material from
|
67
|
+
a header file that is part of the Library. You may convey such object
|
68
|
+
code under terms of your choice, provided that, if the incorporated
|
69
|
+
material is not limited to numerical parameters, data structure
|
70
|
+
layouts and accessors, or small macros, inline functions and templates
|
71
|
+
(ten or fewer lines in length), you do both of the following:
|
72
|
+
|
73
|
+
a) Give prominent notice with each copy of the object code that the
|
74
|
+
Library is used in it and that the Library and its use are
|
75
|
+
covered by this License.
|
76
|
+
|
77
|
+
b) Accompany the object code with a copy of the GNU GPL and this license
|
78
|
+
document.
|
79
|
+
|
80
|
+
4. Combined Works.
|
81
|
+
|
82
|
+
You may convey a Combined Work under terms of your choice that,
|
83
|
+
taken together, effectively do not restrict modification of the
|
84
|
+
portions of the Library contained in the Combined Work and reverse
|
85
|
+
engineering for debugging such modifications, if you also do each of
|
86
|
+
the following:
|
87
|
+
|
88
|
+
a) Give prominent notice with each copy of the Combined Work that
|
89
|
+
the Library is used in it and that the Library and its use are
|
90
|
+
covered by this License.
|
91
|
+
|
92
|
+
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
93
|
+
document.
|
94
|
+
|
95
|
+
c) For a Combined Work that displays copyright notices during
|
96
|
+
execution, include the copyright notice for the Library among
|
97
|
+
these notices, as well as a reference directing the user to the
|
98
|
+
copies of the GNU GPL and this license document.
|
99
|
+
|
100
|
+
d) Do one of the following:
|
101
|
+
|
102
|
+
0) Convey the Minimal Corresponding Source under the terms of this
|
103
|
+
License, and the Corresponding Application Code in a form
|
104
|
+
suitable for, and under terms that permit, the user to
|
105
|
+
recombine or relink the Application with a modified version of
|
106
|
+
the Linked Version to produce a modified Combined Work, in the
|
107
|
+
manner specified by section 6 of the GNU GPL for conveying
|
108
|
+
Corresponding Source.
|
109
|
+
|
110
|
+
1) Use a suitable shared library mechanism for linking with the
|
111
|
+
Library. A suitable mechanism is one that (a) uses at run time
|
112
|
+
a copy of the Library already present on the user's computer
|
113
|
+
system, and (b) will operate properly with a modified version
|
114
|
+
of the Library that is interface-compatible with the Linked
|
115
|
+
Version.
|
116
|
+
|
117
|
+
e) Provide Installation Information, but only if you would otherwise
|
118
|
+
be required to provide such information under section 6 of the
|
119
|
+
GNU GPL, and only to the extent that such information is
|
120
|
+
necessary to install and execute a modified version of the
|
121
|
+
Combined Work produced by recombining or relinking the
|
122
|
+
Application with a modified version of the Linked Version. (If
|
123
|
+
you use option 4d0, the Installation Information must accompany
|
124
|
+
the Minimal Corresponding Source and Corresponding Application
|
125
|
+
Code. If you use option 4d1, you must provide the Installation
|
126
|
+
Information in the manner specified by section 6 of the GNU GPL
|
127
|
+
for conveying Corresponding Source.)
|
128
|
+
|
129
|
+
5. Combined Libraries.
|
130
|
+
|
131
|
+
You may place library facilities that are a work based on the
|
132
|
+
Library side by side in a single library together with other library
|
133
|
+
facilities that are not Applications and are not covered by this
|
134
|
+
License, and convey such a combined library under terms of your
|
135
|
+
choice, if you do both of the following:
|
136
|
+
|
137
|
+
a) Accompany the combined library with a copy of the same work based
|
138
|
+
on the Library, uncombined with any other library facilities,
|
139
|
+
conveyed under the terms of this License.
|
140
|
+
|
141
|
+
b) Give prominent notice with the combined library that part of it
|
142
|
+
is a work based on the Library, and explaining where to find the
|
143
|
+
accompanying uncombined form of the same work.
|
144
|
+
|
145
|
+
6. Revised Versions of the GNU Lesser General Public License.
|
146
|
+
|
147
|
+
The Free Software Foundation may publish revised and/or new versions
|
148
|
+
of the GNU Lesser General Public License from time to time. Such new
|
149
|
+
versions will be similar in spirit to the present version, but may
|
150
|
+
differ in detail to address new problems or concerns.
|
151
|
+
|
152
|
+
Each version is given a distinguishing version number. If the
|
153
|
+
Library as you received it specifies that a certain numbered version
|
154
|
+
of the GNU Lesser General Public License "or any later version"
|
155
|
+
applies to it, you have the option of following the terms and
|
156
|
+
conditions either of that published version or of any later version
|
157
|
+
published by the Free Software Foundation. If the Library as you
|
158
|
+
received it does not specify a version number of the GNU Lesser
|
159
|
+
General Public License, you may choose any version of the GNU Lesser
|
160
|
+
General Public License ever published by the Free Software Foundation.
|
161
|
+
|
162
|
+
If the Library as you received it specifies that a proxy can decide
|
163
|
+
whether future versions of the GNU Lesser General Public License shall
|
164
|
+
apply, that proxy's public statement of acceptance of any version is
|
165
|
+
permanent authorization for you to choose that version for the
|
166
|
+
Library.
|
167
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
= Description
|
2
|
+
RLua is Ruby to Lua bindings library that features almost full coverage of Lua
|
3
|
+
C API, seamless translation of Lua and Ruby objects into each other, calling Lua
|
4
|
+
functions from Ruby and vice versa.
|
5
|
+
|
6
|
+
RLua currently uses Lua 5.1, and is Ruby 1.8, 1.9 and 1.9.1 compatible.
|
7
|
+
|
8
|
+
= Installation
|
9
|
+
RLua is distributed as gem package through rubygems.org, so the procedure is
|
10
|
+
quite usual. It uses native Lua C API, so it will need to compile an extension
|
11
|
+
during installation.
|
12
|
+
|
13
|
+
On Linux, you will need to install Lua development files first.
|
14
|
+
They are packaged as <tt>liblua5.1-dev</tt> in Debian and it's derivatives
|
15
|
+
(like Ubuntu).
|
16
|
+
|
17
|
+
On Windows, you will need MSVC to compile everything. Through I did not tested
|
18
|
+
this (and so cannot provide a detailed description), it should work fine.
|
19
|
+
|
20
|
+
= Example code
|
21
|
+
|
22
|
+
require 'rlua'
|
23
|
+
|
24
|
+
state = Lua::State.new # create Lua interpreter
|
25
|
+
state.__load_stdlib :all # load some standard libraries in it
|
26
|
+
state.__eval "print('hello, world')" # launch some Lua code
|
27
|
+
|
28
|
+
state.value = 10 # set a variable in Ruby
|
29
|
+
state.__eval "print(value)" # show it's value from Lua
|
30
|
+
|
31
|
+
state.__eval "value = 15" # set a variable in Lua
|
32
|
+
p state.value # show it's value from Ruby
|
33
|
+
|
34
|
+
# create a function in Lua
|
35
|
+
state.__eval "function lua_func() print('hello from Lua') end"
|
36
|
+
# launch it from Ruby
|
37
|
+
state.lua_func
|
38
|
+
|
39
|
+
# create a table in Ruby and method in it
|
40
|
+
state.ruby = {
|
41
|
+
'meaning_of_life' => 42,
|
42
|
+
'zaphod' => lambda { |this|
|
43
|
+
p "Meaning of life: #{this.meaning_of_life}"
|
44
|
+
}
|
45
|
+
}
|
46
|
+
# launch that from Lua as instance method
|
47
|
+
state.__eval "ruby:zaphod()"
|
48
|
+
|
49
|
+
= Type conversion
|
50
|
+
Lua and Ruby types are seamlessly translated into each other when calling functions,
|
51
|
+
changing tables and so on. The translation is conservative: you can convert a
|
52
|
+
value from Ruby to Lua, then backwards and will always receive an object that
|
53
|
+
will behave absolutely the same.
|
54
|
+
|
55
|
+
Here is a table of type mapping:
|
56
|
+
<b>Ruby type</b>:: <b>Lua type</b>
|
57
|
+
nil:: nil
|
58
|
+
Boolean (TrueClass or FalseClass):: true or false
|
59
|
+
Fixnum, Bignum or Float:: number
|
60
|
+
Proc:: function
|
61
|
+
String:: string
|
62
|
+
Hash:: table
|
63
|
+
Array:: table (with numeric keys)
|
64
|
+
|
65
|
+
Hashes and Arrays are translated recursively: all keys and values are translated too.
|
66
|
+
Getting any Lua function to Ruby code (even the Ruby proc that was translated
|
67
|
+
before) results in Lua::Function created, and tables behave the same creating
|
68
|
+
Lua::Table object.
|
69
|
+
|
70
|
+
Proc objects are duck-typed: anything that responds to +call+ method is considered
|
71
|
+
Proc.
|
72
|
+
|
73
|
+
Translation of any object not in the list is impossible and will generate an
|
74
|
+
TypeError exception.
|
75
|
+
|
76
|
+
= Notes
|
77
|
+
Most functions are named much like their C API counterparts.
|
78
|
+
|
79
|
+
'Ruby-object-like' table indexing convention is described in Lua::Table,
|
80
|
+
and function calling is described in Lua::Function.
|
81
|
+
|
82
|
+
= Author
|
83
|
+
RLua is currently developed solely by Peter Zotov <whitequark@whitequark.ru>.
|
84
|
+
|
85
|
+
= License
|
86
|
+
This program is free software: you can redistribute it and/or modify
|
87
|
+
it under the terms of the GNU Lesser General Public License as published by
|
88
|
+
the Free Software Foundation, either version 3 of the License, or
|
89
|
+
(at your option) any later version.
|
90
|
+
|
91
|
+
This program is distributed in the hope that it will be useful,
|
92
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
93
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
94
|
+
GNU Lesser General Public License for more details.
|
95
|
+
|
96
|
+
You should have received a copy of the GNU Lesser General Public License
|
97
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/ext/extconf.rb
ADDED
data/ext/rlua.c
ADDED
@@ -0,0 +1,1239 @@
|
|
1
|
+
/*
|
2
|
+
* This file is part of RLua.
|
3
|
+
*
|
4
|
+
* RLua is free software: you can redistribute it and/or modify
|
5
|
+
* it under the terms of the GNU Lesser General Public License as
|
6
|
+
* published by the Free Software Foundation, either version 3 of
|
7
|
+
* the License, or (at your option) any later version.
|
8
|
+
*
|
9
|
+
* RLua is distributed in the hope that it will be useful,
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
* GNU Lesser General Public License for more details.
|
13
|
+
*
|
14
|
+
* You should have received a copy of the GNU Lesser General Public
|
15
|
+
* License along with RLua. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include <ruby.h>
|
19
|
+
#include <lua5.1/lua.h>
|
20
|
+
#include <lua5.1/lauxlib.h>
|
21
|
+
#include <lua5.1/lualib.h>
|
22
|
+
#include <ctype.h>
|
23
|
+
|
24
|
+
VALUE mLua, cLuaState, cLuaMultret, cLuaFunction, cLuaTable;
|
25
|
+
|
26
|
+
static VALUE rlua_makeref(lua_State* state)
|
27
|
+
{
|
28
|
+
VALUE ref;
|
29
|
+
// stack: |objt|...
|
30
|
+
lua_getfield(state, LUA_REGISTRYINDEX, "rlua"); // |refs|objt|...
|
31
|
+
lua_pushvalue(state, -2); // |objt|refs|objt|...
|
32
|
+
ref = INT2FIX(luaL_ref(state, -2)); // |refs|objt|...
|
33
|
+
lua_pop(state, 1); // |objt|...
|
34
|
+
|
35
|
+
return ref;
|
36
|
+
}
|
37
|
+
|
38
|
+
static VALUE rlua_finalize_ref(VALUE id, VALUE rbState)
|
39
|
+
{
|
40
|
+
lua_State* state;
|
41
|
+
Data_Get_Struct(rbState, lua_State, state);
|
42
|
+
|
43
|
+
int ref = FIX2INT(rb_hash_aref(rb_iv_get(rbState, "@refs"), id));
|
44
|
+
|
45
|
+
lua_getfield(state, LUA_REGISTRYINDEX, "rlua");
|
46
|
+
luaL_unref(state, -1, ref);
|
47
|
+
lua_pop(state, 1);
|
48
|
+
|
49
|
+
rb_hash_delete(rb_iv_get(rbState, "@refs"), id);
|
50
|
+
|
51
|
+
return Qnil;
|
52
|
+
}
|
53
|
+
|
54
|
+
static void rlua_add_ref_finalizer(VALUE state, VALUE ref, VALUE object)
|
55
|
+
{
|
56
|
+
rb_hash_aset(rb_iv_get(state, "@refs"), rb_obj_id(object), ref);
|
57
|
+
|
58
|
+
VALUE mObjectSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
|
59
|
+
VALUE proc = rb_proc_new(rlua_finalize_ref, state);
|
60
|
+
rb_funcall(mObjectSpace, rb_intern("define_finalizer"), 2, object, proc);
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE rlua_get_var(lua_State *state)
|
64
|
+
{
|
65
|
+
VALUE rbLuaState;
|
66
|
+
lua_getfield(state, LUA_REGISTRYINDEX, "rlua_state");
|
67
|
+
rbLuaState = (VALUE) lua_touserdata(state, -1);
|
68
|
+
lua_pop(state, 1);
|
69
|
+
|
70
|
+
switch(lua_type(state, -1)) {
|
71
|
+
case LUA_TNONE:
|
72
|
+
case LUA_TNIL:
|
73
|
+
return Qnil;
|
74
|
+
|
75
|
+
case LUA_TTHREAD:
|
76
|
+
rb_warn("cannot pop LUA_TTHREAD");
|
77
|
+
return Qnil;
|
78
|
+
|
79
|
+
case LUA_TUSERDATA:
|
80
|
+
rb_warn("cannot pop LUA_TUSERDATA");
|
81
|
+
return Qnil;
|
82
|
+
|
83
|
+
case LUA_TLIGHTUSERDATA:
|
84
|
+
rb_warn("cannot pop LUA_TLIGHTUSERDATA");
|
85
|
+
return Qnil;
|
86
|
+
|
87
|
+
case LUA_TBOOLEAN:
|
88
|
+
return lua_toboolean(state, -1) ? Qtrue : Qfalse;
|
89
|
+
|
90
|
+
case LUA_TNUMBER:
|
91
|
+
return rb_float_new(lua_tonumber(state, -1));
|
92
|
+
|
93
|
+
case LUA_TSTRING: {
|
94
|
+
size_t length;
|
95
|
+
const char* string;
|
96
|
+
string = lua_tolstring(state, -1, &length);
|
97
|
+
return rb_str_new(string, length);
|
98
|
+
}
|
99
|
+
|
100
|
+
case LUA_TTABLE:
|
101
|
+
return rb_funcall(cLuaTable, rb_intern("new"), 2, rbLuaState, rlua_makeref(state));
|
102
|
+
|
103
|
+
case LUA_TFUNCTION:
|
104
|
+
return rb_funcall(cLuaFunction, rb_intern("new"), 2, rbLuaState, rlua_makeref(state));
|
105
|
+
|
106
|
+
default:
|
107
|
+
rb_bug("rlua_get_var: unknown type %s", lua_typename(state, lua_type(state, -1)));
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
static void rlua_push_var(lua_State *state, VALUE value)
|
112
|
+
{
|
113
|
+
switch (TYPE(value)) {
|
114
|
+
case T_NIL:
|
115
|
+
lua_pushnil(state);
|
116
|
+
break;
|
117
|
+
|
118
|
+
case T_STRING:
|
119
|
+
lua_pushlstring(state, RSTRING_PTR(value), RSTRING_LEN(value));
|
120
|
+
break;
|
121
|
+
|
122
|
+
case T_FIXNUM:
|
123
|
+
lua_pushnumber(state, FIX2INT(value));
|
124
|
+
break;
|
125
|
+
|
126
|
+
case T_BIGNUM:
|
127
|
+
case T_FLOAT:
|
128
|
+
lua_pushnumber(state, NUM2DBL(value));
|
129
|
+
break;
|
130
|
+
|
131
|
+
case T_ARRAY: {
|
132
|
+
int table, i;
|
133
|
+
|
134
|
+
lua_newtable(state);
|
135
|
+
table = lua_gettop(state);
|
136
|
+
for(i = 0; i < RARRAY_LEN(value); i++) {
|
137
|
+
rlua_push_var(state, RARRAY_PTR(value)[i]);
|
138
|
+
lua_rawseti(state, table, i+1);
|
139
|
+
}
|
140
|
+
break;
|
141
|
+
}
|
142
|
+
|
143
|
+
case T_HASH: {
|
144
|
+
int i;
|
145
|
+
VALUE keys;
|
146
|
+
|
147
|
+
lua_newtable(state);
|
148
|
+
keys = rb_funcall(value, rb_intern("keys"), 0);
|
149
|
+
for(i = 0; i < RARRAY_LEN(keys); i++) {
|
150
|
+
VALUE key = RARRAY_PTR(keys)[i];
|
151
|
+
rlua_push_var(state, key);
|
152
|
+
rlua_push_var(state, rb_hash_aref(value, key));
|
153
|
+
lua_settable(state, -3);
|
154
|
+
}
|
155
|
+
break;
|
156
|
+
}
|
157
|
+
|
158
|
+
default:
|
159
|
+
if(value == Qtrue || value == Qfalse) {
|
160
|
+
lua_pushboolean(state, value == Qtrue);
|
161
|
+
} else if(rb_obj_class(value) == cLuaTable || rb_obj_class(value) == cLuaFunction) {
|
162
|
+
lua_getfield(state, LUA_REGISTRYINDEX, "rlua"); // stack: |refs|...
|
163
|
+
lua_rawgeti(state, -1, FIX2INT(rb_iv_get(value, "@ref"))); // |objt|refs|...
|
164
|
+
lua_remove(state, -2); // |objt|...
|
165
|
+
} else if(rb_obj_class(value) == cLuaState) {
|
166
|
+
lua_State* state;
|
167
|
+
Data_Get_Struct(rb_iv_get(value, "@state"), lua_State, state);
|
168
|
+
lua_pushthread(state);
|
169
|
+
} else if(rb_respond_to(value, rb_intern("call"))) {
|
170
|
+
VALUE rbLuaState;
|
171
|
+
lua_getfield(state, LUA_REGISTRYINDEX, "rlua_state");
|
172
|
+
rbLuaState = (VALUE) lua_touserdata(state, -1);
|
173
|
+
lua_pop(state, 1);
|
174
|
+
|
175
|
+
rlua_push_var(state, rb_funcall(cLuaFunction, rb_intern("new"), 2, rbLuaState, value));
|
176
|
+
} else {
|
177
|
+
rb_raise(rb_eTypeError, "wrong argument type %s", rb_obj_classname(value));
|
178
|
+
}
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
static const char* rlua_reader(lua_State* state, void *data, size_t *size)
|
183
|
+
{
|
184
|
+
VALUE code = (VALUE) data;
|
185
|
+
|
186
|
+
if(rb_iv_get(code, "@read") != Qnil) {
|
187
|
+
*size = 0;
|
188
|
+
return NULL;
|
189
|
+
} else {
|
190
|
+
*size = RSTRING_LEN(code);
|
191
|
+
rb_iv_set(code, "@read", Qtrue);
|
192
|
+
return RSTRING_PTR(code);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
static void rlua_load_string(lua_State* state, VALUE code, VALUE chunkname)
|
197
|
+
{
|
198
|
+
Check_Type(code, T_STRING);
|
199
|
+
Check_Type(chunkname, T_STRING);
|
200
|
+
|
201
|
+
// do not interfere with users' string
|
202
|
+
VALUE interm_code = rb_str_new3(code);
|
203
|
+
|
204
|
+
int retval = lua_load(state, rlua_reader, (void*) interm_code, RSTRING_PTR(chunkname));
|
205
|
+
if(retval != 0) {
|
206
|
+
size_t errlen;
|
207
|
+
const char* errstr = lua_tolstring(state, -1, &errlen);
|
208
|
+
VALUE error = rb_str_new(errstr, errlen);
|
209
|
+
lua_pop(state, 1);
|
210
|
+
if(retval == LUA_ERRMEM)
|
211
|
+
rb_exc_raise(rb_exc_new3(rb_eNoMemError, error));
|
212
|
+
else if(retval == LUA_ERRSYNTAX)
|
213
|
+
rb_exc_raise(rb_exc_new3(rb_eSyntaxError, error));
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
static VALUE rlua_pcall(lua_State* state, int argc)
|
218
|
+
{
|
219
|
+
// stack: |argN-arg1|func|...
|
220
|
+
// <N pts.> <1>
|
221
|
+
int base = lua_gettop(state) - 1 - argc;
|
222
|
+
|
223
|
+
int retval = lua_pcall(state, argc, LUA_MULTRET, 0);
|
224
|
+
if(retval != 0) {
|
225
|
+
size_t errlen;
|
226
|
+
const char* errstr = lua_tolstring(state, -1, &errlen);
|
227
|
+
VALUE error = rb_str_new(errstr, errlen);
|
228
|
+
lua_pop(state, 1);
|
229
|
+
|
230
|
+
if(retval == LUA_ERRRUN)
|
231
|
+
rb_exc_raise(rb_exc_new3(rb_eRuntimeError, error));
|
232
|
+
else if(retval == LUA_ERRSYNTAX)
|
233
|
+
rb_exc_raise(rb_exc_new3(rb_eSyntaxError, error));
|
234
|
+
else
|
235
|
+
rb_fatal("unknown lua_pcall return value");
|
236
|
+
} else {
|
237
|
+
VALUE retval;
|
238
|
+
int n = lua_gettop(state) - base;
|
239
|
+
if(n == 0) {
|
240
|
+
return Qnil;
|
241
|
+
} else if(n == 1) {
|
242
|
+
retval = rlua_get_var(state);
|
243
|
+
lua_pop(state, 1);
|
244
|
+
return retval;
|
245
|
+
} else if(n > 1) {
|
246
|
+
retval = rb_ary_new();
|
247
|
+
while(n--) {
|
248
|
+
rb_ary_unshift(retval, rlua_get_var(state));
|
249
|
+
lua_pop(state, 1);
|
250
|
+
}
|
251
|
+
} else {
|
252
|
+
rb_bug("base > top!");
|
253
|
+
}
|
254
|
+
return retval;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
/* :nodoc: */
|
259
|
+
static VALUE rbLuaTable_initialize(int argc, VALUE* argv, VALUE self)
|
260
|
+
{
|
261
|
+
VALUE rbLuaState, ref;
|
262
|
+
rb_scan_args(argc, argv, "11", &rbLuaState, &ref);
|
263
|
+
|
264
|
+
VALUE stateSource = rb_obj_class(rbLuaState);
|
265
|
+
if(stateSource != cLuaState && stateSource != cLuaTable && stateSource != cLuaFunction)
|
266
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected Lua::State, Lua::Table or Lua::Function)",
|
267
|
+
rb_obj_classname(rbLuaState));
|
268
|
+
|
269
|
+
VALUE rbState = rb_iv_get(rbLuaState, "@state");
|
270
|
+
rb_iv_set(self, "@state", rbState);
|
271
|
+
|
272
|
+
if(ref == Qnil) {
|
273
|
+
lua_State* state;
|
274
|
+
Data_Get_Struct(rbState, lua_State, state);
|
275
|
+
|
276
|
+
lua_newtable(state);
|
277
|
+
ref = rlua_makeref(state);
|
278
|
+
lua_pop(state, 1);
|
279
|
+
} else if(TYPE(ref) != T_FIXNUM) {
|
280
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected nil)", rb_obj_classname(ref));
|
281
|
+
}
|
282
|
+
|
283
|
+
rlua_add_ref_finalizer(rbState, ref, self);
|
284
|
+
|
285
|
+
rb_iv_set(self, "@ref", ref);
|
286
|
+
|
287
|
+
return self;
|
288
|
+
}
|
289
|
+
|
290
|
+
/*
|
291
|
+
* call-seq: Lua::Table.next(table, key) -> [ key, value ] or nil
|
292
|
+
*
|
293
|
+
* Iterates over a Lua table referenced by +table+.
|
294
|
+
* This function is analogue for Lua next function, but can be used
|
295
|
+
* even if Lua one is not defined.
|
296
|
+
*
|
297
|
+
* You can use this method yourself, through it is easier to invoke
|
298
|
+
* to_a or to_hash.
|
299
|
+
*/
|
300
|
+
static VALUE rbLuaTable_next(VALUE self, VALUE table, VALUE index)
|
301
|
+
{
|
302
|
+
lua_State* state;
|
303
|
+
Data_Get_Struct(rb_iv_get(table, "@state"), lua_State, state);
|
304
|
+
|
305
|
+
VALUE retval;
|
306
|
+
|
307
|
+
rlua_push_var(state, table); // stack: |this|...
|
308
|
+
rlua_push_var(state, index); // |indx|this|...
|
309
|
+
if(lua_next(state, -2) != 0) { // |valu|key |this|...
|
310
|
+
VALUE value, key;
|
311
|
+
value = rlua_get_var(state); // |valu|key |this|...
|
312
|
+
lua_pop(state, 1); // |key |this|...
|
313
|
+
key = rlua_get_var(state); // |key |this|...
|
314
|
+
lua_pop(state, 2); // ...
|
315
|
+
|
316
|
+
retval = rb_ary_new();
|
317
|
+
rb_ary_push(retval, key);
|
318
|
+
rb_ary_push(retval, value);
|
319
|
+
} else { // |this|...
|
320
|
+
retval = Qnil;
|
321
|
+
lua_pop(state, 1); // ...
|
322
|
+
}
|
323
|
+
|
324
|
+
return retval;
|
325
|
+
}
|
326
|
+
|
327
|
+
/*
|
328
|
+
* call-seq: table[key] -> value
|
329
|
+
*
|
330
|
+
* Returns value associated with +key+ in Lua table. May invoke Lua
|
331
|
+
* +__index+ metamethod.
|
332
|
+
*/
|
333
|
+
static VALUE rbLuaTable_get(VALUE self, VALUE index)
|
334
|
+
{
|
335
|
+
lua_State* state;
|
336
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
337
|
+
|
338
|
+
VALUE value;
|
339
|
+
rlua_push_var(state, self); // stack: |this|...
|
340
|
+
rlua_push_var(state, index); // |indx|this|...
|
341
|
+
lua_gettable(state, -2); // |valu|this|...
|
342
|
+
value = rlua_get_var(state); // |valu|this|...
|
343
|
+
lua_pop(state, 2); // ...
|
344
|
+
|
345
|
+
return value;
|
346
|
+
}
|
347
|
+
|
348
|
+
/*
|
349
|
+
* call-seq: table[key] = value -> value
|
350
|
+
*
|
351
|
+
* Sets value associated with +key+ to +value+ in Lua table. May invoke Lua
|
352
|
+
* +__newindex+ metamethod.
|
353
|
+
*/
|
354
|
+
static VALUE rbLuaTable_set(VALUE self, VALUE index, VALUE value)
|
355
|
+
{
|
356
|
+
lua_State* state;
|
357
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
358
|
+
|
359
|
+
rlua_push_var(state, self); // stack: |this|...
|
360
|
+
rlua_push_var(state, index); // |indx|this|...
|
361
|
+
rlua_push_var(state, value); // |valu|indx|this|...
|
362
|
+
lua_settable(state, -3); // |this|...
|
363
|
+
lua_pop(state, 1); // ...
|
364
|
+
|
365
|
+
return value;
|
366
|
+
}
|
367
|
+
|
368
|
+
/*
|
369
|
+
* call-seq: table.__get(key) -> value
|
370
|
+
*
|
371
|
+
* Returns value associated with +key+ in Lua table without invoking
|
372
|
+
* any Lua metamethod (similar to +rawget+ Lua function).
|
373
|
+
*/
|
374
|
+
static VALUE rbLuaTable_rawget(VALUE self, VALUE index)
|
375
|
+
{
|
376
|
+
lua_State* state;
|
377
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
378
|
+
|
379
|
+
VALUE value;
|
380
|
+
rlua_push_var(state, self); // stack: |this|...
|
381
|
+
rlua_push_var(state, index); // |indx|this|...
|
382
|
+
lua_rawget(state, -2); // |valu|this|...
|
383
|
+
value = rlua_get_var(state); // |valu|this|...
|
384
|
+
lua_pop(state, 2); // ...
|
385
|
+
|
386
|
+
return value;
|
387
|
+
}
|
388
|
+
|
389
|
+
/*
|
390
|
+
* call-seq: table.__set(key, value) -> value
|
391
|
+
*
|
392
|
+
* Sets value associated with +key+ to +value+ in Lua table without invoking
|
393
|
+
* any Lua metamethod (similar to +rawset+ Lua function).
|
394
|
+
*/
|
395
|
+
static VALUE rbLuaTable_rawset(VALUE self, VALUE index, VALUE value)
|
396
|
+
{
|
397
|
+
lua_State* state;
|
398
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
399
|
+
|
400
|
+
rlua_push_var(state, self); // stack: |this|...
|
401
|
+
rlua_push_var(state, index); // |indx|this|...
|
402
|
+
rlua_push_var(state, value); // |valu|indx|this|...
|
403
|
+
lua_rawset(state, -3); // |this|...
|
404
|
+
lua_pop(state, 1); // ...
|
405
|
+
|
406
|
+
return value;
|
407
|
+
}
|
408
|
+
|
409
|
+
/*
|
410
|
+
* call-seq: table.__length -> int
|
411
|
+
*
|
412
|
+
* Returns table length as with Lua length # operator. Will not call
|
413
|
+
* any metamethod because __len metamethod has no effect when
|
414
|
+
* defined on table (and string).
|
415
|
+
*/
|
416
|
+
static VALUE rbLuaTable_length(VALUE self)
|
417
|
+
{
|
418
|
+
lua_State* state;
|
419
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
420
|
+
|
421
|
+
VALUE length;
|
422
|
+
rlua_push_var(state, self); // stack: |this|...
|
423
|
+
length = INT2FIX(lua_objlen(state, -1));
|
424
|
+
lua_pop(state, 1); // ...
|
425
|
+
|
426
|
+
return length;
|
427
|
+
}
|
428
|
+
|
429
|
+
static VALUE rbLuaFunction_call(VALUE self, VALUE args);
|
430
|
+
|
431
|
+
/*
|
432
|
+
* call-seq: table.method_missing(method, *args) -> *values
|
433
|
+
*
|
434
|
+
* This method allows accessing Lua tables much as if they were Ruby
|
435
|
+
* objects.
|
436
|
+
*
|
437
|
+
* <b>Setting values</b> can be done with a standard <i>setter method</i>:
|
438
|
+
* <tt>table.key = value</tt> is equivalent to <tt>table["key"] = value</tt>.
|
439
|
+
*
|
440
|
+
* <b>Getting values</b> is as easy as setting: if the value is not a function,
|
441
|
+
* <tt>table.key</tt> is equivalent to <tt>table["key"]</tt>.
|
442
|
+
*
|
443
|
+
* If some table has a function as value, you can <b>invoke methods</b> on it.
|
444
|
+
* <tt>table.method(arg1, ..., argN)</tt> is equivalent to
|
445
|
+
* <tt>table["method"].call(arg1, ..., argN)</tt>, and
|
446
|
+
* <tt>table.method!(arg1, ..., argN)</tt> is equivalent to
|
447
|
+
* <tt>table["method"].call(table, arg1, ..., argN)</tt>.
|
448
|
+
* To get a reference to function you should use the <tt>table["method"]</tt>
|
449
|
+
* notation.
|
450
|
+
*
|
451
|
+
*/
|
452
|
+
static VALUE rbLuaTable_method_missing(int argc, VALUE* argv, VALUE self)
|
453
|
+
{
|
454
|
+
VALUE id, args;
|
455
|
+
rb_scan_args(argc, argv, "1*", &id, &args);
|
456
|
+
|
457
|
+
VALUE name = rb_str_new2(rb_id2name(rb_to_id(id)));
|
458
|
+
|
459
|
+
int is_method = 0;
|
460
|
+
int is_assign = 0;
|
461
|
+
if(RSTRING_PTR(name)[RSTRING_LEN(name) - 1] == '!')
|
462
|
+
is_method = 1;
|
463
|
+
if(RSTRING_PTR(name)[RSTRING_LEN(name) - 1] == '=')
|
464
|
+
is_assign = 1;
|
465
|
+
|
466
|
+
if(is_method || is_assign)
|
467
|
+
rb_str_resize(name, RSTRING_LEN(name) - 1);
|
468
|
+
|
469
|
+
if(is_assign) {
|
470
|
+
VALUE value;
|
471
|
+
rb_scan_args(argc, argv, "11", &id, &value);
|
472
|
+
return rbLuaTable_set(self, name, value);
|
473
|
+
} else {
|
474
|
+
VALUE value = rbLuaTable_get(self, name);
|
475
|
+
if(value == Qnil) {
|
476
|
+
return rb_call_super(argc, argv);
|
477
|
+
} else if(rb_obj_class(value) != cLuaFunction) {
|
478
|
+
if(is_method)
|
479
|
+
rb_raise(rb_eTypeError, "%s is not a Lua::Function", RSTRING_PTR(name));
|
480
|
+
return value;
|
481
|
+
} else {
|
482
|
+
if(is_method)
|
483
|
+
rb_ary_unshift(args, self);
|
484
|
+
return rbLuaFunction_call(value, args);
|
485
|
+
}
|
486
|
+
}
|
487
|
+
}
|
488
|
+
|
489
|
+
static int call_ruby_proc(lua_State* state)
|
490
|
+
{
|
491
|
+
int i;
|
492
|
+
int argc = lua_gettop(state);
|
493
|
+
VALUE proc, args;
|
494
|
+
|
495
|
+
proc = (VALUE) lua_touserdata(state, lua_upvalueindex(1));
|
496
|
+
args = rb_ary_new();
|
497
|
+
|
498
|
+
for(i = 0; i < argc; i++) {
|
499
|
+
rb_ary_unshift(args, rlua_get_var(state));
|
500
|
+
lua_pop(state, 1);
|
501
|
+
}
|
502
|
+
|
503
|
+
VALUE retval = rb_apply(proc, rb_intern("call"), args);
|
504
|
+
|
505
|
+
if(rb_obj_class(retval) == cLuaMultret) {
|
506
|
+
VALUE array = rb_iv_get(retval, "@args");
|
507
|
+
int i;
|
508
|
+
|
509
|
+
for(i = 0; i < RARRAY_LEN(array); i++)
|
510
|
+
rlua_push_var(state, RARRAY_PTR(array)[i]);
|
511
|
+
|
512
|
+
return RARRAY_LEN(array);
|
513
|
+
} else {
|
514
|
+
rlua_push_var(state, retval);
|
515
|
+
return 1;
|
516
|
+
}
|
517
|
+
}
|
518
|
+
|
519
|
+
/*
|
520
|
+
* call-seq: Lua::Function.new(state, proc)
|
521
|
+
*
|
522
|
+
* Converts a Ruby closure +proc+ to a Lua function in Lua::State represented
|
523
|
+
* by +state+. Note that you generally do not need to call this function
|
524
|
+
* explicitly: any +proc+ or +lambda+ passed as a value for table assignment
|
525
|
+
* will be automagically converted to Lua closure.
|
526
|
+
*/
|
527
|
+
static VALUE rbLuaFunction_initialize(int argc, VALUE* argv, VALUE self)
|
528
|
+
{
|
529
|
+
VALUE rbLuaState, ref = Qnil, func;
|
530
|
+
rb_scan_args(argc, argv, "11", &rbLuaState, &func);
|
531
|
+
|
532
|
+
if(rb_obj_class(rbLuaState) != cLuaState)
|
533
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected Lua::State)", rb_obj_classname(rbLuaState));
|
534
|
+
|
535
|
+
VALUE rbState = rb_iv_get(rbLuaState, "@state");
|
536
|
+
rb_iv_set(self, "@state", rbState);
|
537
|
+
|
538
|
+
lua_State* state;
|
539
|
+
Data_Get_Struct(rbState, lua_State, state);
|
540
|
+
|
541
|
+
VALUE proc = Qnil;
|
542
|
+
|
543
|
+
if(TYPE(func) == T_FIXNUM)
|
544
|
+
ref = func;
|
545
|
+
else if(rb_respond_to(func, rb_intern("call")))
|
546
|
+
proc = func;
|
547
|
+
else
|
548
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", rb_obj_classname(func));
|
549
|
+
|
550
|
+
if(ref == Qnil) {
|
551
|
+
lua_pushlightuserdata(state, (void*) proc);
|
552
|
+
lua_pushcclosure(state, call_ruby_proc, 1);
|
553
|
+
ref = rlua_makeref(state);
|
554
|
+
lua_pop(state, 1);
|
555
|
+
|
556
|
+
// don't allow GC to collect proc
|
557
|
+
rb_iv_set(self, "@proc", proc);
|
558
|
+
}
|
559
|
+
|
560
|
+
rlua_add_ref_finalizer(rbState, ref, self);
|
561
|
+
|
562
|
+
rb_iv_set(self, "@ref", ref);
|
563
|
+
|
564
|
+
return self;
|
565
|
+
}
|
566
|
+
|
567
|
+
/*
|
568
|
+
* call-seq: func.call(*args) -> *values
|
569
|
+
*
|
570
|
+
* Invokes a Lua function in protected environment (like a Lua +xpcall+).
|
571
|
+
*
|
572
|
+
* One value returned in Lua is returned as one value in Ruby; multiple values
|
573
|
+
* returned in Lua are returned as an array of them in Ruby. This convention
|
574
|
+
* allows usage of identical code for calling methods with multiple return
|
575
|
+
* values in both languages.
|
576
|
+
*
|
577
|
+
* While you can easily call Lua procedures and use their return values,
|
578
|
+
* returning multiple values from Ruby is not that easy. RLua cannot
|
579
|
+
* guess whether array returned by Ruby function is a 'real' array or
|
580
|
+
* just several return values, so there is a Lua.multret proxy method for
|
581
|
+
* that purpose. Ruby return values constructed with +multret+ method
|
582
|
+
* are automatically unpacked to multiple return values. Example:
|
583
|
+
*
|
584
|
+
* state = Lua::State.new
|
585
|
+
* state.p = lambda{ |*args| p *args }
|
586
|
+
* state.f1 = Lua::Function.new(state, lambda{ [ 1, 2, 3 ] })
|
587
|
+
* state.f2 = Lua::Function.new(state, lambda{ Lua.multret( 1, 2, 3 ) })
|
588
|
+
* state.__eval("p(f1())") # results in { 1.0, 2.0, 3.0 } Lua table
|
589
|
+
* # shown as array
|
590
|
+
* state.__eval("p(f2())") # results in 1.0, 2.0, 3.0 Lua multiple return values
|
591
|
+
* # shown as three separate values
|
592
|
+
*
|
593
|
+
* Any Lua error that has appeared during the call will be raised as Ruby
|
594
|
+
* exception with message equal to Lua error message.
|
595
|
+
* *Lua error messages are explicitly converted to strings with +lua_tostring+
|
596
|
+
* function.*
|
597
|
+
* Lua errors are mapped as follows:
|
598
|
+
* LUA_ERRMEM:: NoMemError is raised.
|
599
|
+
* LUA_ERRRUN:: RuntimeError is raised.
|
600
|
+
*
|
601
|
+
* Note that if any uncatched exception is raised in Ruby code inside
|
602
|
+
* Lua::Function it will be propagated as Lua error. *In this case the
|
603
|
+
* backtrace is lost!* Catch your exceptions in Ruby code if you want to
|
604
|
+
* keep their backtraces.
|
605
|
+
*
|
606
|
+
* This 'drawback' is intentional: while it is technically possible to
|
607
|
+
* re-raise the same Exception object, the backtrace will lead to re-raise
|
608
|
+
* point anyway.
|
609
|
+
*/
|
610
|
+
static VALUE rbLuaFunction_call(VALUE self, VALUE args)
|
611
|
+
{
|
612
|
+
lua_State* state;
|
613
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
614
|
+
|
615
|
+
int i;
|
616
|
+
VALUE retval;
|
617
|
+
|
618
|
+
rlua_push_var(state, self); // stack: |this|...
|
619
|
+
for(i = 0; i < RARRAY_LEN(args); i++)
|
620
|
+
rlua_push_var(state, RARRAY_PTR(args)[i]);
|
621
|
+
// |argN-arg1|this|...
|
622
|
+
retval = rlua_pcall(state, RARRAY_LEN(args)); // ...
|
623
|
+
|
624
|
+
return retval;
|
625
|
+
}
|
626
|
+
|
627
|
+
/*
|
628
|
+
* call-seq: Lua::State.new
|
629
|
+
*
|
630
|
+
* Creates a new Lua state.
|
631
|
+
*/
|
632
|
+
static VALUE rbLua_initialize(VALUE self)
|
633
|
+
{
|
634
|
+
lua_State* state = luaL_newstate();
|
635
|
+
|
636
|
+
VALUE rbState = Data_Wrap_Struct(rb_cObject, 0, lua_close, state);
|
637
|
+
rb_iv_set(self, "@state", rbState);
|
638
|
+
|
639
|
+
lua_pushlightuserdata(state, (void*) self);
|
640
|
+
lua_setfield(state, LUA_REGISTRYINDEX, "rlua_state");
|
641
|
+
|
642
|
+
lua_newtable(state);
|
643
|
+
lua_setfield(state, LUA_REGISTRYINDEX, "rlua");
|
644
|
+
|
645
|
+
rb_iv_set(rbState, "@refs", rb_hash_new());
|
646
|
+
rb_iv_set(rbState, "@procs", rb_ary_new());
|
647
|
+
|
648
|
+
return self;
|
649
|
+
}
|
650
|
+
|
651
|
+
/*
|
652
|
+
* call-seq: state.__eval(code[, chunkname='=<eval>']) -> *values
|
653
|
+
*
|
654
|
+
* Runs +code+ in Lua interpreter. Optional argument +chunkname+
|
655
|
+
* specifies a string that will be used in error messages and other
|
656
|
+
* debug information as a file name.
|
657
|
+
*
|
658
|
+
* Start +chunkname+ with a @ to make Lua think the following is filename
|
659
|
+
* (e.g. @test.lua); start it with a = to indicate a non-filename stream
|
660
|
+
* (e.g. =stdin). Anything other is interpreted as a plaintext Lua code and
|
661
|
+
* a few starting characters will be shown.
|
662
|
+
*/
|
663
|
+
static VALUE rbLua_eval(int argc, VALUE* argv, VALUE self)
|
664
|
+
{
|
665
|
+
VALUE code, chunkname;
|
666
|
+
rb_scan_args(argc, argv, "11", &code, &chunkname);
|
667
|
+
|
668
|
+
lua_State* state;
|
669
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
670
|
+
|
671
|
+
if(chunkname == Qnil)
|
672
|
+
chunkname = rb_str_new2("=<eval>");
|
673
|
+
|
674
|
+
rlua_load_string(state, code, chunkname);
|
675
|
+
|
676
|
+
return rlua_pcall(state, 0);
|
677
|
+
}
|
678
|
+
|
679
|
+
/*
|
680
|
+
* call-seq: object.__env() -> Lua::Table
|
681
|
+
*
|
682
|
+
* Returns environment table of Lua::State or Lua::Function.
|
683
|
+
*/
|
684
|
+
static VALUE rbLua_get_env(VALUE self)
|
685
|
+
{
|
686
|
+
lua_State* state;
|
687
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
688
|
+
|
689
|
+
VALUE ref;
|
690
|
+
rlua_push_var(state, self); // stack: |this|...
|
691
|
+
lua_getfenv(state, -1); // |envi|this|...
|
692
|
+
ref = rlua_makeref(state); // |envi|this|...
|
693
|
+
lua_pop(state, 2); // ...
|
694
|
+
|
695
|
+
return rb_funcall(cLuaTable, rb_intern("new"), 2, self, ref);
|
696
|
+
}
|
697
|
+
|
698
|
+
/*
|
699
|
+
* call-seq: object.__env=(table) -> table
|
700
|
+
*
|
701
|
+
* Sets environment table for Lua::State or Lua::Function. +table+ may be
|
702
|
+
* a Lua::Table or a Hash.
|
703
|
+
*/
|
704
|
+
static VALUE rbLua_set_env(VALUE self, VALUE env)
|
705
|
+
{
|
706
|
+
lua_State* state;
|
707
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
708
|
+
|
709
|
+
if(rb_obj_class(env) != cLuaTable && TYPE(env) != T_HASH)
|
710
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected Lua::Table or Hash)", rb_obj_classname(env));
|
711
|
+
|
712
|
+
rlua_push_var(state, self); // stack: |this|...
|
713
|
+
rlua_push_var(state, env); // |envi|this|...
|
714
|
+
lua_setfenv(state, -2); // |this|...
|
715
|
+
lua_pop(state, 1); // ...
|
716
|
+
|
717
|
+
return env;
|
718
|
+
}
|
719
|
+
|
720
|
+
/*
|
721
|
+
* call-seq: state.__get_metatable(object) -> Lua::Table or nil
|
722
|
+
*
|
723
|
+
* Returns metatable of any valid Lua object or nil if it is not present.
|
724
|
+
* If you want to get metatables of non-table objects (e.g. numbers)
|
725
|
+
* just pass their Ruby equivalent.
|
726
|
+
*/
|
727
|
+
static VALUE rbLua_get_metatable(VALUE self, VALUE object)
|
728
|
+
{
|
729
|
+
lua_State* state;
|
730
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
731
|
+
|
732
|
+
rlua_push_var(state, object); // stack: |objt|...
|
733
|
+
if(lua_getmetatable(state, -1)) { // |meta|objt|...
|
734
|
+
VALUE ref = rlua_makeref(state); // |meta|objt|...
|
735
|
+
lua_pop(state, 2); // ...
|
736
|
+
|
737
|
+
return rb_funcall(cLuaTable, rb_intern("new"), 2, self, ref);
|
738
|
+
} else { // |objt|...
|
739
|
+
lua_pop(state, 1); // ...
|
740
|
+
|
741
|
+
return Qnil;
|
742
|
+
}
|
743
|
+
}
|
744
|
+
|
745
|
+
/*
|
746
|
+
* call-seq: state.__set_metatable=(object, metatable) -> metatable
|
747
|
+
*
|
748
|
+
* Sets metatable for any valid Lua object. +metatable+ can be Lua::Table or
|
749
|
+
* Hash. If you want to set metatables for non-table objects (e.g. numbers)
|
750
|
+
* just pass their Ruby equivalent.
|
751
|
+
*
|
752
|
+
* # Implement concatenation operator for Lua strnigs.
|
753
|
+
* state = Lua::State.new
|
754
|
+
* state.__set_metatable("", { '__add' => lambda{ |a, b| a + b } })
|
755
|
+
* p state.__eval('return "hello," + " world"') # => "hello, world"
|
756
|
+
*/
|
757
|
+
static VALUE rbLua_set_metatable(VALUE self, VALUE object, VALUE metatable)
|
758
|
+
{
|
759
|
+
lua_State* state;
|
760
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
761
|
+
|
762
|
+
if(rb_obj_class(metatable) != cLuaTable && TYPE(metatable) != T_HASH)
|
763
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected Lua::Table or Hash)", rb_obj_classname(metatable));
|
764
|
+
|
765
|
+
rlua_push_var(state, object); // stack: |objt|...
|
766
|
+
rlua_push_var(state, metatable); // |meta|objt|...
|
767
|
+
lua_setmetatable(state, -2); // |objt|...
|
768
|
+
lua_pop(state, 1); // ...
|
769
|
+
|
770
|
+
return metatable;
|
771
|
+
}
|
772
|
+
|
773
|
+
/*
|
774
|
+
* call-seq: table.__metatable() -> Lua::Table or nil
|
775
|
+
*
|
776
|
+
* Returns metatable of this table or nil if it is not present.
|
777
|
+
*/
|
778
|
+
static VALUE rbLuaTable_get_metatable(VALUE self)
|
779
|
+
{
|
780
|
+
return rbLua_get_metatable(self, self);
|
781
|
+
}
|
782
|
+
|
783
|
+
/*
|
784
|
+
* call-seq: table.__metatable=(metatable) -> metatable
|
785
|
+
*
|
786
|
+
* Sets metatable for this table. +metatable+ can be Lua::Table or Hash.
|
787
|
+
*/
|
788
|
+
static VALUE rbLuaTable_set_metatable(VALUE self, VALUE metatable)
|
789
|
+
{
|
790
|
+
return rbLua_set_metatable(self, self, metatable);
|
791
|
+
}
|
792
|
+
|
793
|
+
/*
|
794
|
+
* call-seq: state[key] -> value
|
795
|
+
*
|
796
|
+
* Returns value of a global variable. Equivalent to __env[key].
|
797
|
+
*/
|
798
|
+
static VALUE rbLua_get_global(VALUE self, VALUE index)
|
799
|
+
{
|
800
|
+
VALUE globals = rbLua_get_env(self);
|
801
|
+
return rbLuaTable_get(globals, index);
|
802
|
+
}
|
803
|
+
|
804
|
+
/*
|
805
|
+
* call-seq: state[key] = value -> value
|
806
|
+
*
|
807
|
+
* Sets value for a global variable. Equivalent to __env[key] = value.
|
808
|
+
*/
|
809
|
+
static VALUE rbLua_set_global(VALUE self, VALUE index, VALUE value)
|
810
|
+
{
|
811
|
+
return rbLuaTable_set(rbLua_get_env(self), index, value);
|
812
|
+
}
|
813
|
+
|
814
|
+
/*
|
815
|
+
* call-seq: this == other -> true or false
|
816
|
+
*
|
817
|
+
* Compares +this+ with +other+. May call +__eq+ metamethod.
|
818
|
+
*/
|
819
|
+
static VALUE rbLua_equal(VALUE self, VALUE other)
|
820
|
+
{
|
821
|
+
lua_State* state;
|
822
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
823
|
+
|
824
|
+
int equal;
|
825
|
+
rlua_push_var(state, self); // stack: |this|...
|
826
|
+
rlua_push_var(state, other); // |othr|this|...
|
827
|
+
equal = lua_equal(state, -1, -2); // |othr|this|...
|
828
|
+
lua_pop(state, 2); // ...
|
829
|
+
|
830
|
+
return equal ? Qtrue : Qfalse;
|
831
|
+
}
|
832
|
+
|
833
|
+
/*
|
834
|
+
* call-seq: this.__equal(other) -> true or false
|
835
|
+
*
|
836
|
+
* Compares +this+ with +other+ without calling any metamethods.
|
837
|
+
*/
|
838
|
+
static VALUE rbLua_rawequal(VALUE self, VALUE other)
|
839
|
+
{
|
840
|
+
lua_State* state;
|
841
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
842
|
+
|
843
|
+
int equal;
|
844
|
+
rlua_push_var(state, self); // stack: |this|...
|
845
|
+
rlua_push_var(state, other); // |othr|this|...
|
846
|
+
equal = lua_rawequal(state, -1, -2); // |othr|this|...
|
847
|
+
lua_pop(state, 2); // ...
|
848
|
+
|
849
|
+
return equal ? Qtrue : Qfalse;
|
850
|
+
}
|
851
|
+
|
852
|
+
/*
|
853
|
+
* call-seq: state.method_missing(method, *args) -> *values
|
854
|
+
*
|
855
|
+
* See Lua::Table#method_missing. Equivalent to __env.method_missing(method, *args).
|
856
|
+
*/
|
857
|
+
static VALUE rbLua_method_missing(int argc, VALUE* argv, VALUE self)
|
858
|
+
{
|
859
|
+
return rbLuaTable_method_missing(argc, argv, rbLua_get_env(self));
|
860
|
+
}
|
861
|
+
|
862
|
+
/*
|
863
|
+
* call-seq: Lua::Multret.new(*values)
|
864
|
+
*
|
865
|
+
* Creates a new Multret object with +values+ inside. Example:
|
866
|
+
*
|
867
|
+
* Lua::Multret.new(1, 2, 3) # three return values
|
868
|
+
*/
|
869
|
+
static VALUE rbLuaMultret_initialize(VALUE self, VALUE args)
|
870
|
+
{
|
871
|
+
rb_iv_set(self, "@args", args);
|
872
|
+
return self;
|
873
|
+
}
|
874
|
+
|
875
|
+
/*
|
876
|
+
* call-seq: Lua.multret(*values)
|
877
|
+
*
|
878
|
+
* Shorthand for Lua::Multret.new.
|
879
|
+
*/
|
880
|
+
static VALUE rbLua_multret(VALUE self, VALUE args)
|
881
|
+
{
|
882
|
+
return rb_funcall(cLuaMultret, rb_intern("new"), 1, args);
|
883
|
+
}
|
884
|
+
|
885
|
+
// bootstrap* are from Lua5.1 source
|
886
|
+
|
887
|
+
static int bootstrap_tonumber (lua_State *L) {
|
888
|
+
int base = luaL_optint(L, 2, 10);
|
889
|
+
if (base == 10) { /* standard conversion */
|
890
|
+
luaL_checkany(L, 1);
|
891
|
+
if (lua_isnumber(L, 1)) {
|
892
|
+
lua_pushnumber(L, lua_tonumber(L, 1));
|
893
|
+
return 1;
|
894
|
+
}
|
895
|
+
}
|
896
|
+
else {
|
897
|
+
const char *s1 = luaL_checkstring(L, 1);
|
898
|
+
char *s2;
|
899
|
+
unsigned long n;
|
900
|
+
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
901
|
+
n = strtoul(s1, &s2, base);
|
902
|
+
if (s1 != s2) { /* at least one valid digit? */
|
903
|
+
while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */
|
904
|
+
if (*s2 == '\0') { /* no invalid trailing characters? */
|
905
|
+
lua_pushnumber(L, (lua_Number)n);
|
906
|
+
return 1;
|
907
|
+
}
|
908
|
+
}
|
909
|
+
}
|
910
|
+
lua_pushnil(L); /* else not a number */
|
911
|
+
return 1;
|
912
|
+
}
|
913
|
+
|
914
|
+
static int bootstrap_tostring (lua_State *L) {
|
915
|
+
luaL_checkany(L, 1);
|
916
|
+
if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */
|
917
|
+
return 1; /* use its value */
|
918
|
+
switch (lua_type(L, 1)) {
|
919
|
+
case LUA_TNUMBER:
|
920
|
+
lua_pushstring(L, lua_tostring(L, 1));
|
921
|
+
break;
|
922
|
+
case LUA_TSTRING:
|
923
|
+
lua_pushvalue(L, 1);
|
924
|
+
break;
|
925
|
+
case LUA_TBOOLEAN:
|
926
|
+
lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false"));
|
927
|
+
break;
|
928
|
+
case LUA_TNIL:
|
929
|
+
lua_pushliteral(L, "nil");
|
930
|
+
break;
|
931
|
+
default:
|
932
|
+
lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1));
|
933
|
+
break;
|
934
|
+
}
|
935
|
+
return 1;
|
936
|
+
}
|
937
|
+
|
938
|
+
static int bootstrap_error (lua_State *L) {
|
939
|
+
int level = luaL_optint(L, 2, 1);
|
940
|
+
lua_settop(L, 1);
|
941
|
+
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
|
942
|
+
luaL_where(L, level);
|
943
|
+
lua_pushvalue(L, 1);
|
944
|
+
lua_concat(L, 2);
|
945
|
+
}
|
946
|
+
return lua_error(L);
|
947
|
+
}
|
948
|
+
|
949
|
+
static int bootstrap_type (lua_State *L) {
|
950
|
+
luaL_checkany(L, 1);
|
951
|
+
lua_pushstring(L, luaL_typename(L, 1));
|
952
|
+
return 1;
|
953
|
+
}
|
954
|
+
|
955
|
+
|
956
|
+
static int bootstrap_next (lua_State *L) {
|
957
|
+
luaL_checktype(L, 1, LUA_TTABLE);
|
958
|
+
lua_settop(L, 2); /* create a 2nd argument if there isn't one */
|
959
|
+
if (lua_next(L, 1))
|
960
|
+
return 2;
|
961
|
+
else {
|
962
|
+
lua_pushnil(L);
|
963
|
+
return 1;
|
964
|
+
}
|
965
|
+
}
|
966
|
+
|
967
|
+
|
968
|
+
static int bootstrap_pairs (lua_State *L) {
|
969
|
+
luaL_checktype(L, 1, LUA_TTABLE);
|
970
|
+
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
|
971
|
+
lua_pushvalue(L, 1); /* state, */
|
972
|
+
lua_pushnil(L); /* and initial value */
|
973
|
+
return 3;
|
974
|
+
}
|
975
|
+
|
976
|
+
|
977
|
+
static int bootstrap_inext (lua_State *L) {
|
978
|
+
int i = luaL_checkint(L, 2);
|
979
|
+
luaL_checktype(L, 1, LUA_TTABLE);
|
980
|
+
i++; /* next value */
|
981
|
+
lua_pushinteger(L, i);
|
982
|
+
lua_rawgeti(L, 1, i);
|
983
|
+
return (lua_isnil(L, -1)) ? 0 : 2;
|
984
|
+
}
|
985
|
+
|
986
|
+
|
987
|
+
static int bootstrap_ipairs (lua_State *L) {
|
988
|
+
luaL_checktype(L, 1, LUA_TTABLE);
|
989
|
+
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
|
990
|
+
lua_pushvalue(L, 1); /* state, */
|
991
|
+
lua_pushinteger(L, 0); /* and initial value */
|
992
|
+
return 3;
|
993
|
+
}
|
994
|
+
|
995
|
+
static int bootstrap_unpack (lua_State *L) {
|
996
|
+
int i, e, n;
|
997
|
+
luaL_checktype(L, 1, LUA_TTABLE);
|
998
|
+
i = luaL_optint(L, 2, 1);
|
999
|
+
e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
|
1000
|
+
n = e - i + 1; /* number of elements */
|
1001
|
+
if (n <= 0) return 0; /* empty range */
|
1002
|
+
luaL_checkstack(L, n, "table too big to unpack");
|
1003
|
+
for (; i<=e; i++) /* push arg[i...e] */
|
1004
|
+
lua_rawgeti(L, 1, i);
|
1005
|
+
return n;
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
|
1009
|
+
static int bootstrap_select (lua_State *L) {
|
1010
|
+
int n = lua_gettop(L);
|
1011
|
+
if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
|
1012
|
+
lua_pushinteger(L, n-1);
|
1013
|
+
return 1;
|
1014
|
+
}
|
1015
|
+
else {
|
1016
|
+
int i = luaL_checkint(L, 1);
|
1017
|
+
if (i < 0) i = n + i;
|
1018
|
+
else if (i > n) i = n;
|
1019
|
+
luaL_argcheck(L, 1 <= i, 1, "index out of range");
|
1020
|
+
return n - i;
|
1021
|
+
}
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
static int bootstrap_assert (lua_State *L) {
|
1025
|
+
luaL_checkany(L, 1);
|
1026
|
+
if (!lua_toboolean(L, 1))
|
1027
|
+
return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
|
1028
|
+
return lua_gettop(L);
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
static int bootstrap_pcall (lua_State *L) {
|
1032
|
+
int status;
|
1033
|
+
luaL_checkany(L, 1);
|
1034
|
+
status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
|
1035
|
+
lua_pushboolean(L, (status == 0));
|
1036
|
+
lua_insert(L, 1);
|
1037
|
+
return lua_gettop(L); /* return status + all results */
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
static int bootstrap_xpcall (lua_State *L) {
|
1041
|
+
int status;
|
1042
|
+
luaL_checkany(L, 2);
|
1043
|
+
lua_settop(L, 2);
|
1044
|
+
lua_insert(L, 1); /* put error function under function to be called */
|
1045
|
+
status = lua_pcall(L, 0, LUA_MULTRET, 1);
|
1046
|
+
lua_pushboolean(L, (status == 0));
|
1047
|
+
lua_replace(L, 1);
|
1048
|
+
return lua_gettop(L); /* return status + all results */
|
1049
|
+
}
|
1050
|
+
|
1051
|
+
static const
|
1052
|
+
struct { char* name; lua_CFunction func; }
|
1053
|
+
stdlib[] = {
|
1054
|
+
{ "type", bootstrap_type },
|
1055
|
+
{ "next", bootstrap_next },
|
1056
|
+
{ "tonumber", bootstrap_tonumber },
|
1057
|
+
{ "tostring", bootstrap_tostring },
|
1058
|
+
{ "unpack", bootstrap_unpack },
|
1059
|
+
{ "select", bootstrap_select },
|
1060
|
+
{ "error", bootstrap_error },
|
1061
|
+
{ "assert", bootstrap_assert },
|
1062
|
+
{ "pcall", bootstrap_pcall },
|
1063
|
+
{ "xpcall", bootstrap_xpcall },
|
1064
|
+
};
|
1065
|
+
|
1066
|
+
/*
|
1067
|
+
* call-seq: state.__bootstrap() -> true
|
1068
|
+
*
|
1069
|
+
* Deploys an absolute minimum of functions required to write minimally
|
1070
|
+
* useful Lua programs. This is really a subset of Lua _base_ library
|
1071
|
+
* (copied from Lua 5.1 sources) that may be handy if you don't like standard
|
1072
|
+
* function layout. All of these functions can be implemented in pure Ruby,
|
1073
|
+
* but that will slow down Lua code incredibly.
|
1074
|
+
*
|
1075
|
+
* <b>If you want to get familiar layout described in Lua documentation, check
|
1076
|
+
* #__load_stdlib function.</b>
|
1077
|
+
*
|
1078
|
+
* Exact list of functions defined: type, next, tonumber, tostring, unpack,
|
1079
|
+
* select, error, assert, pcall, xpcall.
|
1080
|
+
*/
|
1081
|
+
static VALUE rbLua_bootstrap(VALUE self)
|
1082
|
+
{
|
1083
|
+
lua_State* state;
|
1084
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
1085
|
+
|
1086
|
+
int nf;
|
1087
|
+
for(nf = 0; nf < sizeof(stdlib) / sizeof(stdlib[0]); nf++) {
|
1088
|
+
lua_pushcclosure(state, stdlib[nf].func, 0);
|
1089
|
+
lua_setglobal(state, stdlib[nf].name);
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
lua_pushcfunction(state, bootstrap_next);
|
1093
|
+
lua_pushcclosure(state, bootstrap_pairs, 1);
|
1094
|
+
lua_setglobal(state, "pairs");
|
1095
|
+
|
1096
|
+
lua_pushcfunction(state, bootstrap_inext);
|
1097
|
+
lua_pushcclosure(state, bootstrap_ipairs, 1);
|
1098
|
+
lua_setglobal(state, "ipairs");
|
1099
|
+
|
1100
|
+
return Qtrue;
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
static void rlua_openlib(lua_State* state, lua_CFunction func)
|
1104
|
+
{
|
1105
|
+
lua_pushcfunction(state, func);
|
1106
|
+
lua_call(state, 0, 0);
|
1107
|
+
}
|
1108
|
+
|
1109
|
+
/*
|
1110
|
+
* call-seq: state.__load_stdlib(*libs) -> true
|
1111
|
+
*
|
1112
|
+
* Loads Lua standard libraries. There are two ways of calling this function:
|
1113
|
+
*
|
1114
|
+
* If you will call it as __load_stdlib(:all), it is equivalent to calling
|
1115
|
+
* C +luaL_openlibs+ function.
|
1116
|
+
*
|
1117
|
+
* If you will pass it symbolized names of separate libraries (like :base),
|
1118
|
+
* it is equivalent to calling corresponding +luaopen_*+ functions.
|
1119
|
+
*
|
1120
|
+
* Examples:
|
1121
|
+
*
|
1122
|
+
* # Load all standard libraries
|
1123
|
+
* state = Lua::State.new
|
1124
|
+
* state.__load_stdlib :all
|
1125
|
+
*
|
1126
|
+
* # Load only math, string and table libraries
|
1127
|
+
* state = Lua::State.new
|
1128
|
+
* state.__load_stdlib :math, :string, :table
|
1129
|
+
*
|
1130
|
+
* Exact list of libraries recognized: <tt>:base</tt>, <tt>:table</tt>,
|
1131
|
+
* <tt>:math</tt>, <tt>:string</tt>, <tt>:debug</tt>, <tt>:io</tt>,
|
1132
|
+
* <tt>:os</tt>, <tt>:package</tt>.
|
1133
|
+
* <b>Anything not included in this list will be silently ignored.</b>
|
1134
|
+
*/
|
1135
|
+
static VALUE rbLua_load_stdlib(VALUE self, VALUE args)
|
1136
|
+
{
|
1137
|
+
lua_State* state;
|
1138
|
+
Data_Get_Struct(rb_iv_get(self, "@state"), lua_State, state);
|
1139
|
+
|
1140
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern("all")))) {
|
1141
|
+
luaL_openlibs(state);
|
1142
|
+
} else {
|
1143
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern("base"))))
|
1144
|
+
rlua_openlib(state, luaopen_base);
|
1145
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern(LUA_TABLIBNAME))))
|
1146
|
+
rlua_openlib(state, luaopen_table);
|
1147
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern(LUA_MATHLIBNAME))))
|
1148
|
+
rlua_openlib(state, luaopen_math);
|
1149
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern(LUA_STRLIBNAME))))
|
1150
|
+
rlua_openlib(state, luaopen_string);
|
1151
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern(LUA_DBLIBNAME))))
|
1152
|
+
rlua_openlib(state, luaopen_debug);
|
1153
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern(LUA_IOLIBNAME))))
|
1154
|
+
rlua_openlib(state, luaopen_io);
|
1155
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern(LUA_OSLIBNAME))))
|
1156
|
+
rlua_openlib(state, luaopen_os);
|
1157
|
+
if(rb_ary_includes(args, ID2SYM(rb_intern(LUA_LOADLIBNAME))))
|
1158
|
+
rlua_openlib(state, luaopen_package);
|
1159
|
+
}
|
1160
|
+
|
1161
|
+
return Qtrue;
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
void Init_rlua()
|
1165
|
+
{
|
1166
|
+
/*
|
1167
|
+
* Main module that encapsulates all RLua classes and methods.
|
1168
|
+
*/
|
1169
|
+
mLua = rb_define_module("Lua");
|
1170
|
+
|
1171
|
+
/*
|
1172
|
+
* Lua::State represents Lua interpreter state which is one thread of
|
1173
|
+
* execution.
|
1174
|
+
*/
|
1175
|
+
cLuaState = rb_define_class_under(mLua, "State", rb_cObject);
|
1176
|
+
rb_define_method(cLuaState, "initialize", rbLua_initialize, 0);
|
1177
|
+
rb_define_method(cLuaState, "__eval", rbLua_eval, -1);
|
1178
|
+
rb_define_method(cLuaState, "__bootstrap", rbLua_bootstrap, 0);
|
1179
|
+
rb_define_method(cLuaState, "__load_stdlib", rbLua_load_stdlib, -2);
|
1180
|
+
rb_define_method(cLuaState, "__env", rbLua_get_env, 0);
|
1181
|
+
rb_define_method(cLuaState, "__env=", rbLua_set_env, 1);
|
1182
|
+
rb_define_method(cLuaState, "__get_metatable", rbLua_get_metatable, 1);
|
1183
|
+
rb_define_method(cLuaState, "__set_metatable", rbLua_set_metatable, 2);
|
1184
|
+
rb_define_method(cLuaState, "[]", rbLua_get_global, 1);
|
1185
|
+
rb_define_method(cLuaState, "[]=", rbLua_set_global, 2);
|
1186
|
+
rb_define_method(cLuaState, "method_missing", rbLua_method_missing, -1);
|
1187
|
+
|
1188
|
+
/*
|
1189
|
+
* An intermediate object assisting return of multiple values from Ruby.
|
1190
|
+
* See description of Lua::Function#call.
|
1191
|
+
*/
|
1192
|
+
cLuaMultret = rb_define_class_under(mLua, "Multret", rb_cObject);
|
1193
|
+
rb_define_method(cLuaMultret, "initialize", rbLuaMultret_initialize, 1);
|
1194
|
+
rb_define_singleton_method(mLua, "multret", rbLua_multret, -2);
|
1195
|
+
|
1196
|
+
/*
|
1197
|
+
* Lua::Function represents a Lua function, may it be a native (i.e.
|
1198
|
+
* defined in Lua code) function or Ruby closure.
|
1199
|
+
*
|
1200
|
+
* Lua::Function is duck-typed like a +proc+ (implements +call+ method)
|
1201
|
+
* and thus can be used as a replacement, through it cannot be converted
|
1202
|
+
* to block. You can use
|
1203
|
+
*
|
1204
|
+
* some_method(parameters) { |*args| lua_func.call(*args) }
|
1205
|
+
*
|
1206
|
+
* instead.
|
1207
|
+
*
|
1208
|
+
* See also important notes about exceptions and return values in
|
1209
|
+
* #call function.
|
1210
|
+
*/
|
1211
|
+
cLuaFunction = rb_define_class_under(mLua, "Function", rb_cObject);
|
1212
|
+
rb_define_method(cLuaFunction, "initialize", rbLuaFunction_initialize, -1);
|
1213
|
+
rb_define_method(cLuaFunction, "call", rbLuaFunction_call, -2);
|
1214
|
+
rb_define_method(cLuaFunction, "__env", rbLua_get_env, 0);
|
1215
|
+
rb_define_method(cLuaFunction, "__env=", rbLua_set_env, 1);
|
1216
|
+
rb_define_method(cLuaFunction, "__equal", rbLua_rawequal, 1);
|
1217
|
+
rb_define_method(cLuaFunction, "==", rbLua_equal, 1);
|
1218
|
+
|
1219
|
+
/*
|
1220
|
+
* A Ruby Lua::Table object represents a *reference* to a Lua table.
|
1221
|
+
* As it is a reference, any changes made to table in Lua are visible in
|
1222
|
+
* Ruby and vice versa.
|
1223
|
+
*
|
1224
|
+
* See also #method_missing function for a convenient way to access tables.
|
1225
|
+
*/
|
1226
|
+
cLuaTable = rb_define_class_under(mLua, "Table", rb_cObject);
|
1227
|
+
rb_define_singleton_method(cLuaTable, "next", rbLuaTable_next, 2);
|
1228
|
+
rb_define_method(cLuaTable, "initialize", rbLuaTable_initialize, -1);
|
1229
|
+
rb_define_method(cLuaTable, "__metatable", rbLuaTable_get_metatable, 0);
|
1230
|
+
rb_define_method(cLuaTable, "__metatable=", rbLuaTable_set_metatable, 1);
|
1231
|
+
rb_define_method(cLuaTable, "__length", rbLuaTable_length, 0);
|
1232
|
+
rb_define_method(cLuaTable, "__get", rbLuaTable_rawget, 1);
|
1233
|
+
rb_define_method(cLuaTable, "__set", rbLuaTable_rawset, 2);
|
1234
|
+
rb_define_method(cLuaTable, "__equal", rbLua_rawequal, 1);
|
1235
|
+
rb_define_method(cLuaTable, "[]", rbLuaTable_get, 1);
|
1236
|
+
rb_define_method(cLuaTable, "[]=", rbLuaTable_set, 2);
|
1237
|
+
rb_define_method(cLuaTable, "==", rbLua_equal, 1);
|
1238
|
+
rb_define_method(cLuaTable, "method_missing", rbLuaTable_method_missing, -1);
|
1239
|
+
}
|