File: luna2.h

package info (click to toggle)
metakit 2.4.3-3
  • links: PTS
  • area: main
  • in suites: woody
  • size: 6,468 kB
  • ctags: 3,548
  • sloc: xml: 29,455; cpp: 23,339; sh: 9,051; tcl: 1,195; python: 577; makefile: 254; ansic: 14
file content (205 lines) | stat: -rw-r--r-- 6,097 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// luna2.h -- C++ interface wrapper for Lua
// $Id: luna2.h,v 1.2 2001/11/03 23:59:22 wcvs Exp $
// This is part of MetaKit, see http://www.equi4.com/metakit/

#include <assert.h>

extern "C" {
  #include <lua.h>
  #include <lauxlib.h>
}

class Lua {
  lua_State* _state;
  int _pos;
  int _res;
public:
  Lua (lua_State* L, int n_) : _state (L), _pos (n_), _res (0) {}

  bool more() const { return _pos < lua_gettop(_state); }
  void done() const { assert(!more()); }

  Lua& operator++ () { assert(more()); ++_pos; return *this; }
  int nextarg() { assert(more()); return ++_pos; }
  operator lua_State* () const { return _state; }
  int numresults() const { return _res; }

  // required args
  operator bool () const { return !lua_isnil(_state, _pos); }
  operator int () const { return luaL_check_int(_state, _pos); }
  operator long () const { return luaL_check_long(_state, _pos); }
  operator double () const { return luaL_check_number(_state, _pos); }
  operator char () const { return *luaL_check_string(_state, _pos); }
  operator const char* () const { return luaL_check_string(_state, _pos); }

  // optional args
  Lua& operator>> (bool& a) { if (more()) a = ++*this; return *this; }
  Lua& operator>> (int& a) { if (more()) a = ++*this; return *this; }
  Lua& operator>> (long& a) { if (more()) a = ++*this; return *this; }
  Lua& operator>> (double& a) { if (more()) a = ++*this; return *this; }
  Lua& operator>> (char& a) { if (more()) a = ++*this; return *this; }
  Lua& operator>> (const char*& a) { if (more()) a = ++*this; return *this; }

  // results
  Lua& operator<< (bool a) {
    if (a)
      lua_pushnumber(_state, 1);
    else
      lua_pushnil(_state);
    ++_res;
    return *this;
  }
  Lua& operator<< (int a) {
    lua_pushnumber(_state, a);
    ++_res;
    return *this;
  }
  Lua& operator<< (long a) {
    lua_pushnumber(_state, a);
    ++_res;
    return *this;
  }
  Lua& operator<< (double a) {
    lua_pushnumber(_state, a);
    ++_res;
    return *this;
  }
  Lua& operator<< (char a) {
    lua_pushlstring(_state, &a, 1);
    ++_res;
    return *this;
  }
  Lua& operator<< (const char* a) {
    lua_pushstring(_state, a);
    ++_res;
    return *this;
  }
  Lua& pushusertag(void* a, int t) {
    lua_pushusertag(_state, a, t);
    ++_res;
    return *this;
  }
};

// Inspired by the luna.h code of Lenny Palozzi - lenny.palozzi@home.net

template <class T> class Luna {
  /* constructs T objects */
  static int constructor(lua_State* L) {
    Lua lua (L, 1);
    (void) create(lua);
    return lua.numresults();
  }
  /* member function dispatcher */
  static int proxy(lua_State* L) {
    assert(lua_tag(L, 1) == otag);
    T* obj = static_cast<T*>(lua_touserdata(L,1));
    int i = static_cast<int>(lua_tonumber(L,-1)); 
    lua_pop(L, 1);
    Lua lua (L, 1);
    (obj->*(T::regTable[i].mfunc))(lua);
    return lua.numresults();
  }
  /* method call dispatcher */
  static int methodcall(lua_State* L) {
    assert(lua_tag(L, 1) == otag); // table or userdata
    assert(lua_istable(L, -1) && lua_tag(L, -1) == otag);
    assert(lua_isstring(L, 2));
    lua_pushvalue(L,2);
    lua_rawget(L, -2);
    return 1;
  }
  /* member access dispatcher */
  static int getmember(lua_State* L) {
    //assert(lua_isuserdata(L, 1) && lua_tag(L, 1) == otag);
    assert(lua_tag(L, 1) == otag); // table or userdata
    assert(lua_istable(L, -1) && lua_tag(L, -1) == otag);
    assert(lua_isstring(L, 2));
    lua_pushvalue(L,2);
    lua_rawget(L, -2);
    lua_pushvalue(L,1);
    lua_call(L, 1, 1);
    return 1;
  }
#if 0
  /* member modify dispatcher */
  static int setmember(lua_State* L) {
    //assert(lua_isuserdata(L, 1) && lua_tag(L, 1) == otag);
    assert(lua_tag(L, 1) == otag); // table or userdata
    assert(lua_istable(L, -1) && lua_tag(L, -1) == otag);
    assert(lua_isstring(L, 2));
    lua_pushvalue(L,2);
    lua_rawget(L, -2);
    lua_pushvalue(L, 1);
    lua_pushnumber(L, 1);
    lua_call(L, 2, 1);
    return 1;
  }
#endif
  /* releases objects */
  static int gc_obj(lua_State* L) {
    T* obj = static_cast<T*>(lua_touserdata(L, -1));
    delete obj;
    return 0;
  }
protected: 
  Luna(); /* hide default constructor */
public:
  static int otag;
  /* member function map */
  struct RegType { const char* name; void(T::*mfunc)(Lua&); };      
  /* register class T */
  static void Register(lua_State* L, int data =0) {
    lua_newtable(L);
    if (otag == 0) {
      otag = lua_newtag(L);
      	// TODO: there's a major mixup in here - the table should only
	// get the function tm, and the constructed userdata objects
	// should get the gc and gettable tm's, using a 2nd tag number
      lua_pushcfunction(L, &Luna<T>::constructor);
      lua_settagmethod(L, otag, "function");
      lua_pushcfunction(L, &Luna<T>::gc_obj);
      lua_settagmethod(L, otag, "gc");
      lua_pushvalue(L,-1);
      lua_pushcclosure(L, data ? &Luna<T>::getmember
	  		       : &Luna<T>::methodcall, 1);
      lua_settagmethod(L, otag, "gettable");
#if 0
      if (data > 1) {
	lua_pushvalue(L,-1);
	lua_pushcclosure(L, &Luna<T>::setmember, 1);
	lua_settagmethod(L, otag, "settable");
      }
#endif
    }
    lua_settag(L,otag);
    /* register the member functions */
    for (int i=0; T::regTable[i].name; i++) {
      lua_pushstring(L, T::regTable[i].name);
      lua_pushnumber(L, i);
      lua_pushcclosure(L, &Luna<T>::proxy, 1);
      lua_settable(L, -3);
    }
    lua_setglobal(L, T::className);
  }
  /* constructs T objects and returns them for use in C++ */
  static T* create(Lua& lua) {
    T* obj = new T(lua); /* new T */
    assert(otag != 0);
    lua.pushusertag(obj,otag);
    return obj; /* also leaves userdata object on Lua stack */
  }
  /* grab an arg of the proper type */
  static T* getarg(Lua& lua, int n = 0) {
    if (n == 0) n = lua.nextarg();
    void* p = lua_touserdata(lua, n);
    return p != 0 && lua_tag(lua, n) == otag ? (T*) p : 0;
  }
};

template <class T> int Luna<T>::otag = 0;

template <class T> Lua& operator>> (Lua& lua, T*& arg) {
  if (lua.more()) arg = Luna<T>::getarg(lua);
  return lua;
}