Accessing Table's table value from C++

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Accessing Table's table value from C++

Initial-N
Hi all,
 
I have a question regarding to accessing table value.
Assuming I have two table in Lua (as an initial script).
 
In Lua:
global_objects = {
 effectype = {
  water = {99, 3330, 88},
  air = {1, 2, 8}
 }
}
simpleTable = { effectype = 1 }

In my C++ code is something like this,

// this accpet integer index
void ReadTableVar(const char * table, int index, void *value)
{
 lua_getglobal(mLuaState, table);
 if(!lua_istable(mLuaState, -1)) {return;}
 if(lua_isnil(mLuaState, -1)) {return;}
 FindTableValue(mLuaState, index); // this loops though the table until "index"
 *((double *)value) = (double)lua_tonumber(mLuaState, -1);
 
// this accept string index
void ReadTableVar(const char * table, const char * index, void *value)
{
 lua_getglobal(mLuaState, table);
 if(!lua_istable(mLuaState, -1)) {return;}
 if(lua_isnil(mLuaState, -1)) {return;}
 FindTableValue(mLuaState, index); // this loops though the table until "index"
 *((double *)value) = (double)lua_tonumber(mLuaState, -1);
 
using this code, it works if call is,
ReadTableVar("simpleTable", "effectype", &value);
However, it does not work, if the call is,
ReadTableVar("global_objects.effectype.water", 1, &value);
When I trace through the code, I find that !lua_istable is true,
as a result, it returns.
I tried this in the lua interactive enviroment, it actually tells me that
global_objects.effectype.water is a table.
I have no idea why my C++ code does not evaluate global_objects.effectype.water
as a table. Should I actauly need to separate global_objects effectype and water
and explicitly do the table traverse?
 
(Currently I am using Lua 4.0.1)
Thanks in advance.
Nelson



Post your free ad now! Yahoo! Canada Personals
Reply | Threaded
Open this post in threaded view
|

Re: Accessing Table's table value from C++

Ashwin Hirschi-2

[snip<]
I have no idea why my C++ code does not evaluate global_objects.effectype.water
as a table. Should I actauly need to separate global_objects effectype and water
and explicitly do the table traverse?

I don't think lua_getglobal handles the entire 'path' for you.

You need to do a lua_getglobal on "global_objects" and then access the result table using lua_gettable. This way you'll find the "effectype" [only 1 't'?] table and can call lua_gettable again to get to the "water" table.

Best check the reference manual for more details.

Also, doing type-checking on results is good, but it looks like checking for nil after you've ensured it's a table is a bit redundant.

I hope this helps.

Ashwin.
--
no signature is a signature.

Reply | Threaded
Open this post in threaded view
|

Re: Accessing Table's table value from C++

Initial-N
Thanks, Ashwin,
It works!!! 
After getting the global_objects table, I need to push a string (effecttype), then do a lua_gettable(L, -2) in order to get the effecttype table.
Therefore, entrie sequence is:
 
lua_getglobal(L, "global_objects");
lua_pushstring(L, "effecttype");
lua_gettable(L, -2);
lua_pushstring(L, "water");
lua_gettable(L, -2);
 
One thing I have not yet clear is, what exactly are happening in the stack when calling the sequence above.
I know calling lua_getglobal give me a table which live in the lua global environment, but I wonder if  the entire table STRUCTURE is push on the top of the stack, or any magic tag is being pushed so that the stack is able to give me the next table when do the pushstring and gettable.
 
Sorry for the newbie question, but I am fairly confused how the lua stack work. Any tips can help me to monitor the stack?
 
Thanks again!
Nelson

Ashwin Hirschi <[hidden email]> wrote:

[snip<]
> I have no idea why my C++ code does not evaluate global_objects.effectype.water
> as a table. Should I actauly need to separate global_objects effectype and water
> and explicitly do the table traverse?

I don't think lua_getglobal handles the entire 'path' for you.

You need to do a lua_getglobal on "global_objects" and then access the result table using lua_gettable. This way you'll find the "effectype" [only 1 't'?] table and can call lua_gettable again to get to the "water" table.

Best check the reference manual for more details.

Also, doing type-checking on results is good, but it looks like checking for nil after you've ensured it's a table is a bit redundant.

I hope this helps.

Ashwin.
--
no signature is a signature.



Post your free ad now! Yahoo! Canada Personals
Reply | Threaded
Open this post in threaded view
|

Re: Accessing Table's table value from C++

David Olofson
On Wednesday 02 February 2005 16.31, Initial-N wrote:
> Thanks, Ashwin, 
> It works!!! 
> After getting the global_objects table, I need to push a string 
(effecttype), then do a lua_gettable(L, -2) in order to get the 
effecttype table.
> Therefore, entrie sequence is:
>  
> lua_getglobal(L, "global_objects");
> lua_pushstring(L, "effecttype");
> lua_gettable(L, -2);
> lua_pushstring(L, "water");
> lua_gettable(L, -2);
>  
> One thing I have not yet clear is, what exactly are happening in the 
stack when calling the sequence above.

I don't know exactly what Lua does, but assuming it works like your 
average stack based machine:

> lua_getglobal(L, "global_objects");

-1: table global_objects

> lua_pushstring(L, "effecttype");

-2: table global_objects
-1: string "effecttype"

> lua_gettable(L, -2);

(The operation pops the two arguments and pushes the result.)

-1: table "effecttype"

> lua_pushstring(L, "water");

-2: table "effecttype"
-1: string "water"

> lua_gettable(L, -2);

("Same procedure as every year, James!")

-1: <whatever is at index "water" in table "effecttype">


Then again, my own VM (the one in EEL) doesn't have a stack in the 
usual sense (the closest match would be the linked list of closures 
that forms when functions call each other), so what do I know!? :-D


> I know calling lua_getglobal give me a table which live in the lua
> global environment, but I wonder if  the entire table STRUCTURE is
> push on the top of the stack, or any magic tag is being pushed so
> that the stack is able to give me the next table when do the
> pushstring and gettable.

I believe the Lua stack (like EEL's "registers") consists of so called 
"tagged values" - that is, something like this:

typedef struct
{
 int type;
 union
 {
  int integer;
  double real;
  TOBJECT *objref;
  ...
 } v;
} TVALUE;

So, when you "get" an object as a result (or pass one, for that 
matter), it's actually just a value set to {type = TYPE_OBJECT, 
v.objref = <address of object>} - that is, a wrapped pointer to an 
instance.


//David Olofson - Programmer, Composer, Open Source Advocate

.- Audiality -----------------------------------------------.
|  Free/Open Source audio engine for games and multimedia.  |
| MIDI, modular synthesis, real time effects, scripting,... |
`-----------------------------------> http://audiality.org -'
   --- http://olofson.net --- http://www.reologica.se ---

Reply | Threaded
Open this post in threaded view
|

Re: Accessing Table's table value from C++

Adrian Sietsma
In reply to this post by Initial-N
Initial-N wrote:

One thing I have not yet clear is, what exactly are happening in the stack when calling the sequence above.
 see d.o.'s reply

I know calling lua_getglobal give me a table which live in the lua global environment, but I wonder if the entire table STRUCTURE is push on the top of the stack, or any magic tag is being pushed so that the stack is able to give me the next table when do the pushstring and gettable.
the latter. all tables (and strings) are magic references.

Adrian

Reply | Threaded
Open this post in threaded view
|

Re: Accessing Table's table value from C++

Ashwin Hirschi-2
In reply to this post by Initial-N

Thanks, Ashwin,
It works!!!

Glad to hear it.

After getting the global_objects table, I need to push a string (effecttype), then do a lua_gettable(L, -2) in order to get the effecttype table.
Therefore, entrie sequence is:
lua_getglobal(L, "global_objects");
lua_pushstring(L, "effecttype");
lua_gettable(L, -2);
lua_pushstring(L, "water");
lua_gettable(L, -2);

Yes, this is the smallest sequence.

Of course, having a little error-checking in there wouldn't hurt [unless you're absolutely sure all your data is always available]. For instance, if the 2nd table would somehow be missing, Lua would (quite correctly) throw an alert during your last lua_gettable call. Depending on circumstances, that could be a bit embarrassing, I think.

One thing I have not yet clear is, what exactly are happening in the stack when calling the sequence above.

The reference manual clearly describes how particular Lua API functions change the stack [i.e. what is popped off and pushed onto it]. And you don't need anything else to properly interact with Lua. So, really, don't worry about it too much! [:-)]

Then again, if you're just curious about what actually happens: use the source! I think Lua is very well-written, and it doesn't take too much effort to get somewhat familiar with it.

Obviously, it helps if your development environment has some sort of code-navigation support. That way you don't spend an inordinate amount of time hunting for scraps of code. Many IDEs provide tools to help you. But I use ctags, since I do all of my programming using Vim.

Last but not least, the Lua team provides a nice way to navigate the source by browser:

	http://www.lua.org/source/

This is always an enjoyable way to spend a lazy Sunday afternoon [;-)].

Have fun!

Ashwin.
--
no signature is a signature.

Reply | Threaded
Open this post in threaded view
|

Re: Accessing Table's table value from C++

Javier Guerra Giraldez
On Saturday 05 February 2005 9:12 am, Ashwin Hirschi wrote:
> Of course, having a little error-checking in there wouldn't hurt [unless
> you're absolutely sure all your data is always available]. For instance, if
> the 2nd table would somehow be missing, Lua would (quite correctly) throw
> an alert during your last lua_gettable call. Depending on circumstances,
> that could be a bit embarrassing, I think.

that's one thing i think could be different.  in this case, the C calling code 
should do all the error-checking, no argue with that.  but in Lua, i find 
lots of times i want to do something like this:

var = table[index].field

but if i'm not sure that [index] is present in that table, i have to split in 
two:

local temp = table[index]
if temp then var=temp.field else var=nil end

usually, i don't care about intermediate values, just if any part of the table 
fetchs fails, the whole expression should be nil, and i'd be happy to check 
the result just once and not every step.

in short, i'd like that 
(nil)[anything] == nil
instead of failing

does anybody object to this?


-- 
Javier

Attachment: pgphrqBjaerTK.pgp
Description: PGP signature

Reply | Threaded
Open this post in threaded view
|

Re: Accessing Table's table value from C++

Rici Lake-2

On 5-Feb-05, at 9:51 AM, Javier Guerra wrote:

in short, i'd like that
(nil)[anything] == nil
instead of failing

does anybody object to this?

The reasonable objection is that this would serve to hide
programming errors, although I personally could live with
it. However, it might be worthwhile considering alternatives.

For example, it would be possible to define the following
syntaxes:
  table?key
  table?[expr]
  func?(args)
and so on, which would declare that the programmer anticipated
that the left hand expression might evaluate to nil or false,
in which case the value should be the left hand expression.
This could optionally short-circuit the evaluation of the
entire sequence of postfix operators, so that:

  t?foo.bar

would effectively mean that 'foo' might not be a key of t, but
if it is, it must itself have a 'bar' key, which some might
find intuitive.

Another option, which has also been suggested from time to time,
is to add some sort of __toboolean metamethod, which would allow
the creation of an object which behaved the way you are suggesting
'nil' behave. Then you could attach that object as a default value
for a table which you wished to have that sort of behaviour:

  NOVALUE = {}
  do
    local novalue_meta = {}
    function novalue_meta:__index() return NOVALUE end
    function novalue_meta:__toboolean() return false end
    setmetatable(NOVALUE, novalue_meta)

    local opt_meta = {}
    function opt_meta:__index() return NOVALUE end

    function OptTable()
      return setmetatable({}, opt_meta)
    end
  end

Yet another interesting possibility is an extension to the
syntax of 'if' (and maybe 'while') to create a local:

  if subtable = table[index] then
    -- subtable is in scope in this chunk
    var = subtable.field
   else
    -- subtable is not in scope here
    var = nil
  end


Reply | Threaded
Open this post in threaded view
|

(nil)[anything] == nil (was Re: Accessing Table's table value from C++)

Petite Abeille
In reply to this post by Javier Guerra Giraldez

On Feb 05, 2005, at 15:51, Javier Guerra wrote:

in short, i'd like that
(nil)[anything] == nil
instead of failing

does anybody object to this?

Yes. Strongly. There is a bare minimum amount of sanity that the Lua VM should rightly expect. It already way to lax in many aspects.

Just my 2 reais (?).

Cheers

--
PA, Onnay Equitursay
http://alt.textdrive.com/


Reply | Threaded
Open this post in threaded view
|

Re: (nil)[anything] == nil (was Re: Accessing Table's table value from C++)

Ben Sunshine-Hill
On Sat, 5 Feb 2005 17:14:03 +0100, PA <[hidden email]> wrote:
> 
> On Feb 05, 2005, at 15:51, Javier Guerra wrote:
> 
> > in short, i'd like that
> > (nil)[anything] == nil
> > instead of failing
> >
> > does anybody object to this?
> 
> Yes. Strongly. There is a bare minimum amount of sanity that the Lua VM
> should rightly expect. It already way to lax in many aspects.
> 

It's also easy to emulate with (tbl or {})[field], if you really need
this odd behavior in a particular circumstance.

Ben

Reply | Threaded
Open this post in threaded view
|

Re: Accessing Table's table value from C++

Mark Hamburg-4
In reply to this post by Javier Guerra Giraldez
You can write this as:

    local temp = table[index]
    var = temp and temp.field

Or one can write:

    var = (table[index] or {}).field
        -- better if we use a pre-allocated empty table

That being said, I too have wished for a simpler way to do nil-friendly
operations.

http://lua-users.org/lists/lua-l/2004-06/msg00645.html

Mark

on 2/5/05 6:51 AM, Javier Guerra at [hidden email] wrote:

> On Saturday 05 February 2005 9:12 am, Ashwin Hirschi wrote:
>> Of course, having a little error-checking in there wouldn't hurt [unless
>> you're absolutely sure all your data is always available]. For instance, if
>> the 2nd table would somehow be missing, Lua would (quite correctly) throw
>> an alert during your last lua_gettable call. Depending on circumstances,
>> that could be a bit embarrassing, I think.
> 
> that's one thing i think could be different.  in this case, the C calling code
> should do all the error-checking, no argue with that.  but in Lua, i find
> lots of times i want to do something like this:
> 
> var = table[index].field
> 
> but if i'm not sure that [index] is present in that table, i have to split in
> two:
> 
> local temp = table[index]
> if temp then var=temp.field else var=nil end
> 
> usually, i don't care about intermediate values, just if any part of the table
> fetchs fails, the whole expression should be nil, and i'd be happy to check
> the result just once and not every step.
> 
> in short, i'd like that
> (nil)[anything] == nil
> instead of failing
> 
> does anybody object to this?
>