Logo Search packages:      
Sourcecode: ocropus version File versions  Download package

tolua_event.c

/* tolua: event functions
** Support code for Lua bindings.
** Written by Waldemar Celes
** TeCGraf/PUC-Rio
** Apr 2003
** $Id: $
*/

/* This code is free software; you can redistribute it and/or modify it.
** The software provided hereunder is on an "as is" basis, and
** the author has no obligation to provide maintenance, support, updates,
** enhancements, or modifications.
*/

#include <stdio.h>

#include "tolua++.h"

/* Store at ubox
      * It stores, creating the corresponding table if needed,
      * the pair key/value in the corresponding ubox table
*/
static void storeatubox (lua_State* L, int lo)
{
      #ifdef LUA_VERSION_NUM
            lua_getfenv(L, lo);
            if (lua_rawequal(L, -1, TOLUA_NOPEER)) {
                  lua_pop(L, 1);
                  lua_newtable(L);
                  lua_pushvalue(L, -1);
                  lua_setfenv(L, lo);     /* stack: k,v,table  */
            };
            lua_insert(L, -3);
            lua_settable(L, -3); /* on lua 5.1, we trade the "tolua_peers" lookup for a settable call */
            lua_pop(L, 1);
      #else
       /* stack: key value (to be stored) */
            lua_pushstring(L,"tolua_peers");
            lua_rawget(L,LUA_REGISTRYINDEX);        /* stack: k v ubox */
            lua_pushvalue(L,lo);
            lua_rawget(L,-2);                       /* stack: k v ubox ubox[u] */
            if (!lua_istable(L,-1))
            {
                  lua_pop(L,1);                          /* stack: k v ubox */
                  lua_newtable(L);                       /* stack: k v ubox table */
                  lua_pushvalue(L,1);
                  lua_pushvalue(L,-2);                   /* stack: k v ubox table u table */
                  lua_rawset(L,-4);                      /* stack: k v ubox ubox[u]=table */
            }
            lua_insert(L,-4);                       /* put table before k */
            lua_pop(L,1);                           /* pop ubox */
            lua_rawset(L,-3);                       /* store at table */
            lua_pop(L,1);                           /* pop ubox[u] */
      #endif
}

/* Module index function
*/
static int module_index_event (lua_State* L)
{
      lua_pushstring(L,".get");
      lua_rawget(L,-3);
      if (lua_istable(L,-1))
      {
            lua_pushvalue(L,2);  /* key */
            lua_rawget(L,-2);
            if (lua_iscfunction(L,-1))
            {
                  lua_call(L,0,1);
                  return 1;
            }
            else if (lua_istable(L,-1))
                  return 1;
      }
      /* call old index meta event */
      if (lua_getmetatable(L,1))
      {
            lua_pushstring(L,"__index");
            lua_rawget(L,-2);
            lua_pushvalue(L,1);
            lua_pushvalue(L,2);
            if (lua_isfunction(L,-1))
            {
                  lua_call(L,2,1);
                  return 1;
            }
            else if (lua_istable(L,-1))
            {
                  lua_gettable(L,-3);
                  return 1;
            }
      }
      lua_pushnil(L);
      return 1;
}

/* Module newindex function
*/
static int module_newindex_event (lua_State* L)
{
      lua_pushstring(L,".set");
      lua_rawget(L,-4);
      if (lua_istable(L,-1))
      {
            lua_pushvalue(L,2);  /* key */
            lua_rawget(L,-2);
            if (lua_iscfunction(L,-1))
            {
                  lua_pushvalue(L,1); /* only to be compatible with non-static vars */
                  lua_pushvalue(L,3); /* value */
                  lua_call(L,2,0);
                  return 0;
            }
      }
      /* call old newindex meta event */
      if (lua_getmetatable(L,1) && lua_getmetatable(L,-1))
      {
            lua_pushstring(L,"__newindex");
            lua_rawget(L,-2);
            if (lua_isfunction(L,-1))
            {
             lua_pushvalue(L,1);
             lua_pushvalue(L,2);
             lua_pushvalue(L,3);
                  lua_call(L,3,0);
            }
      }
      lua_settop(L,3);
      lua_rawset(L,-3);
      return 0;
}

/* Class index function
      * If the object is a userdata (ie, an object), it searches the field in
      * the alternative table stored in the corresponding "ubox" table.
*/
static int class_index_event (lua_State* L)
{
 int t = lua_type(L,1);
      if (t == LUA_TUSERDATA)
      {
            /* Access alternative table */
            #ifdef LUA_VERSION_NUM /* new macro on version 5.1 */
            lua_getfenv(L,1);
            if (!lua_rawequal(L, -1, TOLUA_NOPEER)) {
                  lua_pushvalue(L, 2); /* key */
                  lua_gettable(L, -2); /* on lua 5.1, we trade the "tolua_peers" lookup for a gettable call */
                  if (!lua_isnil(L, -1))
                        return 1;
            };
            #else
            lua_pushstring(L,"tolua_peers");
            lua_rawget(L,LUA_REGISTRYINDEX);        /* stack: obj key ubox */
            lua_pushvalue(L,1);
            lua_rawget(L,-2);                       /* stack: obj key ubox ubox[u] */
            if (lua_istable(L,-1))
            {
                  lua_pushvalue(L,2);  /* key */
                  lua_rawget(L,-2);                      /* stack: obj key ubox ubox[u] value */
                  if (!lua_isnil(L,-1))
                        return 1;
            }
            #endif
            lua_settop(L,2);                        /* stack: obj key */
            /* Try metatables */
            lua_pushvalue(L,1);                     /* stack: obj key obj */
            while (lua_getmetatable(L,-1))
            {                                       /* stack: obj key obj mt */
                  lua_remove(L,-2);                      /* stack: obj key mt */
                  if (lua_isnumber(L,2))                 /* check if key is a numeric value */
                  {
                        /* try operator[] */
                        lua_pushstring(L,".geti");
                        lua_rawget(L,-2);                      /* stack: obj key mt func */
                        if (lua_isfunction(L,-1))
                        {
                              lua_pushvalue(L,1);
                              lua_pushvalue(L,2);
                              lua_call(L,2,1);
                              return 1;
                        }
                  }
                  else
                  {
                   lua_pushvalue(L,2);                    /* stack: obj key mt key */
                        lua_rawget(L,-2);                      /* stack: obj key mt value */
                        if (!lua_isnil(L,-1))
                              return 1;
                        else
                              lua_pop(L,1);
                        /* try C/C++ variable */
                        lua_pushstring(L,".get");
                        lua_rawget(L,-2);                      /* stack: obj key mt tget */
                        if (lua_istable(L,-1))
                        {
                              lua_pushvalue(L,2);
                              lua_rawget(L,-2);                      /* stack: obj key mt value */
                              if (lua_iscfunction(L,-1))
                              {
                                    lua_pushvalue(L,1);
                                    lua_pushvalue(L,2);
                                    lua_call(L,2,1);
                                    return 1;
                              }
                              else if (lua_istable(L,-1))
                              {
                                    /* deal with array: create table to be returned and cache it in ubox */
                                    void* u = *((void**)lua_touserdata(L,1));
                                    lua_newtable(L);                /* stack: obj key mt value table */
                                    lua_pushstring(L,".self");
                                    lua_pushlightuserdata(L,u);
                                    lua_rawset(L,-3);               /* store usertype in ".self" */
                                    lua_insert(L,-2);               /* stack: obj key mt table value */
                                    lua_setmetatable(L,-2);         /* set stored value as metatable */
                                    lua_pushvalue(L,-1);            /* stack: obj key met table table */
                                    lua_pushvalue(L,2);             /* stack: obj key mt table table key */
                                    lua_insert(L,-2);               /*  stack: obj key mt table key table */
                                    storeatubox(L,1);               /* stack: obj key mt table */
                                    return 1;
                              }
                        }
                  }
                  lua_settop(L,3);
            }
            lua_pushnil(L);
            return 1;
      }
      else if (t== LUA_TTABLE)
      {
            module_index_event(L);
            return 1;
      }
      lua_pushnil(L);
      return 1;
}

/* Newindex function
      * It first searches for a C/C++ varaible to be set.
      * Then, it either stores it in the alternative ubox table (in the case it is
      * an object) or in the own table (that represents the class or module).
*/
static int class_newindex_event (lua_State* L)
{
 int t = lua_type(L,1);
      if (t == LUA_TUSERDATA)
      {
       /* Try accessing a C/C++ variable to be set */
            lua_getmetatable(L,1);
            while (lua_istable(L,-1))                /* stack: t k v mt */
            {
                  if (lua_isnumber(L,2))                 /* check if key is a numeric value */
                  {
                        /* try operator[] */
                        lua_pushstring(L,".seti");
                        lua_rawget(L,-2);                      /* stack: obj key mt func */
                        if (lua_isfunction(L,-1))
                        {
                              lua_pushvalue(L,1);
                              lua_pushvalue(L,2);
                              lua_pushvalue(L,3);
                              lua_call(L,3,0);
                              return 0;
                        }
                  }
                  else
                  {
                        lua_pushstring(L,".set");
                        lua_rawget(L,-2);                      /* stack: t k v mt tset */
                        if (lua_istable(L,-1))
                        {
                              lua_pushvalue(L,2);
                              lua_rawget(L,-2);                     /* stack: t k v mt tset func */
                              if (lua_iscfunction(L,-1))
                              {
                                    lua_pushvalue(L,1);
                                    lua_pushvalue(L,3);
                                    lua_call(L,2,0);
                                    return 0;
                              }
                              lua_pop(L,1);                          /* stack: t k v mt tset */
                        }
                        lua_pop(L,1);                           /* stack: t k v mt */
                        if (!lua_getmetatable(L,-1))            /* stack: t k v mt mt */
                              lua_pushnil(L);
                        lua_remove(L,-2);                       /* stack: t k v mt */
                  }
            }
       lua_settop(L,3);                          /* stack: t k v */

            /* then, store as a new field */
            storeatubox(L,1);
      }
      else if (t== LUA_TTABLE)
      {
            module_newindex_event(L);
      }
      return 0;
}

static int class_call_event(lua_State* L) {

      if (lua_istable(L, 1)) {
            lua_pushstring(L, ".call");
            lua_rawget(L, 1);
            if (lua_isfunction(L, -1)) {

                  lua_insert(L, 1);
                  lua_call(L, lua_gettop(L)-1, 1);

                  return 1;
            };
      };
      tolua_error(L,"Attempt to call a non-callable object.",NULL);
      return 0;
};

static int do_operator (lua_State* L, const char* op)
{
      if (lua_isuserdata(L,1))
      {
            /* Try metatables */
            lua_pushvalue(L,1);                     /* stack: op1 op2 */
            while (lua_getmetatable(L,-1))
            {                                       /* stack: op1 op2 op1 mt */
                  lua_remove(L,-2);                      /* stack: op1 op2 mt */
                  lua_pushstring(L,op);                  /* stack: op1 op2 mt key */
                  lua_rawget(L,-2);                      /* stack: obj key mt func */
                  if (lua_isfunction(L,-1))
                  {
                        lua_pushvalue(L,1);
                        lua_pushvalue(L,2);
                        lua_call(L,2,1);
                        return 1;
                  }
                  lua_settop(L,3);
            }
      }
      tolua_error(L,"Attempt to perform operation on an invalid operand",NULL);
      return 0;
}

static int class_add_event (lua_State* L)
{
      return do_operator(L,".add");
}

static int class_sub_event (lua_State* L)
{
      return do_operator(L,".sub");
}

static int class_mul_event (lua_State* L)
{
      return do_operator(L,".mul");
}

static int class_div_event (lua_State* L)
{
      return do_operator(L,".div");
}

static int class_lt_event (lua_State* L)
{
      return do_operator(L,".lt");
}

static int class_le_event (lua_State* L)
{
      return do_operator(L,".le");
}

static int class_eq_event (lua_State* L)
{
      /* copying code from do_operator here to return false when no operator is found */
      if (lua_isuserdata(L,1))
      {
            /* Try metatables */
            lua_pushvalue(L,1);                     /* stack: op1 op2 */
            while (lua_getmetatable(L,-1))
            {                                       /* stack: op1 op2 op1 mt */
                  lua_remove(L,-2);                      /* stack: op1 op2 mt */
                  lua_pushstring(L,".eq");                  /* stack: op1 op2 mt key */
                  lua_rawget(L,-2);                      /* stack: obj key mt func */
                  if (lua_isfunction(L,-1))
                  {
                        lua_pushvalue(L,1);
                        lua_pushvalue(L,2);
                        lua_call(L,2,1);
                        return 1;
                  }
                  lua_settop(L,3);
            }
      }

      lua_settop(L, 3);
      lua_pushboolean(L, 0);
      return 1;
}

/*
static int class_gc_event (lua_State* L)
{
      void* u = *((void**)lua_touserdata(L,1));
      fprintf(stderr, "collecting: looking at %p\n", u);
      lua_pushstring(L,"tolua_gc");
      lua_rawget(L,LUA_REGISTRYINDEX);
      lua_pushlightuserdata(L,u);
      lua_rawget(L,-2);
      if (lua_isfunction(L,-1))
      {
            lua_pushvalue(L,1);
            lua_call(L,1,0);
            lua_pushlightuserdata(L,u);
            lua_pushnil(L);
            lua_rawset(L,-3);
      }
      lua_pop(L,2);
      return 0;
}
*/
TOLUA_API int class_gc_event (lua_State* L)
{
      void* u = *((void**)lua_touserdata(L,1));
      int top;
      /*fprintf(stderr, "collecting: looking at %p\n", u);*/
      /*
      lua_pushstring(L,"tolua_gc");
      lua_rawget(L,LUA_REGISTRYINDEX);
      */
      lua_pushvalue(L, lua_upvalueindex(1));
      lua_pushlightuserdata(L,u);
      lua_rawget(L,-2);            /* stack: gc umt    */
      lua_getmetatable(L,1);       /* stack: gc umt mt */
      /*fprintf(stderr, "checking type\n");*/
      top = lua_gettop(L);
      if (tolua_fast_isa(L,top,top-1, lua_upvalueindex(2))) /* make sure we collect correct type */
      {
            /*fprintf(stderr, "Found type!\n");*/
            /* get gc function */
            lua_pushliteral(L,".collector");
            lua_rawget(L,-2);           /* stack: gc umt mt collector */
            if (lua_isfunction(L,-1)) {
                  /*fprintf(stderr, "Found .collector!\n");*/
            }
            else {
                  lua_pop(L,1);
                  /*fprintf(stderr, "Using default cleanup\n");*/
                  lua_pushcfunction(L,tolua_default_collect);
            }

            lua_pushvalue(L,1);         /* stack: gc umt mt collector u */
            lua_call(L,1,0);

            lua_pushlightuserdata(L,u); /* stack: gc umt mt u */
            lua_pushnil(L);             /* stack: gc umt mt u nil */
            lua_rawset(L,-5);           /* stack: gc umt mt */
      }
      lua_pop(L,3);
      return 0;
}


/* Register module events
      * It expects the metatable on the top of the stack
*/
TOLUA_API void tolua_moduleevents (lua_State* L)
{
      lua_pushstring(L,"__index");
      lua_pushcfunction(L,module_index_event);
      lua_rawset(L,-3);
      lua_pushstring(L,"__newindex");
      lua_pushcfunction(L,module_newindex_event);
      lua_rawset(L,-3);
}

/* Check if the object on the top has a module metatable
*/
TOLUA_API int tolua_ismodulemetatable (lua_State* L)
{
      int r = 0;
      if (lua_getmetatable(L,-1))
      {
            lua_pushstring(L,"__index");
            lua_rawget(L,-2);
            r = (lua_tocfunction(L,-1) == module_index_event);
            lua_pop(L,2);
      }
      return r;
}

/* Register class events
      * It expects the metatable on the top of the stack
*/
TOLUA_API void tolua_classevents (lua_State* L)
{
      lua_pushstring(L,"__index");
      lua_pushcfunction(L,class_index_event);
      lua_rawset(L,-3);
      lua_pushstring(L,"__newindex");
      lua_pushcfunction(L,class_newindex_event);
      lua_rawset(L,-3);

      lua_pushstring(L,"__add");
      lua_pushcfunction(L,class_add_event);
      lua_rawset(L,-3);
      lua_pushstring(L,"__sub");
      lua_pushcfunction(L,class_sub_event);
      lua_rawset(L,-3);
      lua_pushstring(L,"__mul");
      lua_pushcfunction(L,class_mul_event);
      lua_rawset(L,-3);
      lua_pushstring(L,"__div");
      lua_pushcfunction(L,class_div_event);
      lua_rawset(L,-3);

      lua_pushstring(L,"__lt");
      lua_pushcfunction(L,class_lt_event);
      lua_rawset(L,-3);
      lua_pushstring(L,"__le");
      lua_pushcfunction(L,class_le_event);
      lua_rawset(L,-3);
      lua_pushstring(L,"__eq");
      lua_pushcfunction(L,class_eq_event);
      lua_rawset(L,-3);

      lua_pushstring(L,"__call");
      lua_pushcfunction(L,class_call_event);
      lua_rawset(L,-3);

      lua_pushstring(L,"__gc");
      lua_pushstring(L, "tolua_gc_event");
      lua_rawget(L, LUA_REGISTRYINDEX);
      /*lua_pushcfunction(L,class_gc_event);*/
      lua_rawset(L,-3);
}


Generated by  Doxygen 1.6.0   Back to index