[Home] [Downloads] [Search] [Help/forum]

Gammon Software Solutions forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Development
. . -> [Subject]  Playing with GetNestedFunction

Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?

Playing with GetNestedFunction

[Reply to this subject]  Reply to this subject   [New subject]  Start a new subject   [Refresh] Refresh page


Posted by Twisol   USA  (2,230 posts)  [Biography] bio
Date Tue 14 Sep 2010 07:01 AM (UTC)  quote  ]

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
[Go to top] 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.


795 views.

[Reply to this subject]  Reply to this subject   [New subject]  Start a new subject   [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

[Home]

Written by Nick Gammon - 5K

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( http://www.gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Internet Contents Rating Association (ICRA) - 2K]    [Web site powered by FutureQuest.Net]