Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ MUSHclient ➜ Development ➜ Playing with GetNestedFunction

Playing with GetNestedFunction

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Twisol   USA  (2,257 posts)  Bio
Date Tue 14 Sep 2010 07:01 AM (UTC)

Amended on Tue 14 Sep 2010 07:02 AM (UTC) by Twisol

Message
So this might be a little frivolous, but I wanted to look at GetNestedFunction to see if it cleaned up after itself on the Lua stack. It does, but I wanted to make the usage semantics a bit more obvious, i.e. yes, you do have to pop from the stack afterwards.

This is the refactoring I've done:

// Given a name of the form "table.function", retrieves a function
// from a set of nested tables. (There can be 0 or more "table"s in the name.)
// Pushes the named function to the stack on success, and nil on failure.
bool GetNestedFunction (lua_State * L, const char * sName, const bool bRaiseError)
  {
  // L: ...

  vector<string> v;
  StringToVector (sName, v, ".", true);

  // get the method from the end, leaving only table names in the vector
  string sMethod = v.back ();
  v.pop_back ();

  // run down the vector to get to the table containing the method.
  // Start with the globals table, _G.
  lua_pushvalue(L, LUA_GLOBALSINDEX); // L: ... _G
  string sTable = "_G";

  vector<string>::const_iterator iter = v.begin ();
  vector<string>::const_iterator end = v.end ();
  for (; iter != end; ++iter)
    {
    // L: ... parent
    if (!lua_istable (L, -1))
      break; // it's not a table, so we can't get the method we wanted

    // pull the child table out, and remove the parent
    lua_getfield (L, -1, iter->c_str ()); // L: ... parent, child
    lua_remove (L, -2); // L: ... child

    sTable = *iter;
    }
  // L: ... table

  // make sure the last thing was a table
  if (lua_istable (L, -1))
    {
    // get the method and remove the table
    lua_getfield (L, -1, sMethod.c_str ()); // L: ... table, function
    lua_remove (L, -2); // L: ... function

    // make sure we have a function
    if (lua_isfunction (L, -1))
      return true; // L: ... function
    else
      sTable = sMethod; // for the error message at the bottom
    }
  // ... unknown

  if (bRaiseError)
    ::UMessageBox (TFormat ("Cannot find the function '%s' - item '%s' is %s",
                            sMethod, 
                            sTable.c_str (),
                            luaL_typename (L, -1)), 
                   MB_ICONEXCLAMATION);

  lua_pop (L, 1); // L: ...
  lua_pushnil (L); // L: ... nil
  return false; // L: ... nil
  }


Mostly, I tightened up the semantics such that 'nil' is always at the top of the stack if it can't resolve the method. I also replaced the lua_pushstring/lua_gettable pairs with lua_getfield because it's more concise (and I couldn't resist).

Given the nil/function stack result, this function could easily return void, and callers could act based on the value at the top of the stack. The error message could be pushed to the stack after the nil, which the calling code could display as it wishes. I didn't do these because I don't want to touch the calling code yet.

I'm not putting this into an active refactoring branch, I just thought I'd have some fun experimenting with it. Ideally, this function wouldn't deal with showing errors to the user directly, because it's orthogonal to the function's job. I'd prefer usage like this (in Lua pseudocode):
local func, err = get_nested_function("foo.bar")
if func == nil then
  error(err)
end


Anyways, I just thought I'd throw it out there.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


6,101 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.