Sub-item (property/index) data access
// push the 'print' function // method 1 sgs_PushGlobalByName( C, "print" ); // method 2 sgs_PushEnv( C ); sgs_PushProperty( C, -1, "print" ); sgs_PopSkip( C, 1, 1 ); // method 3 sgs_PushEnv( C ); sgs_PushString( C, "print" ); sgs_PushIndex( C, sgs_StackItem( C, -2 ), sgs_StackItem( C, -1 ), 1 );
- Sub-items are variables that can be found inside other variables via property/index access.
- The API offers a huge variety of functions that deal with sub-items.
- It is important to note the cascading nature of these API functions - if one doesn't do the exact thing, there's usually a function that gives more control.
- All of these three global property retrieval methods offer various levels of control.
- To take more control means also taking responsibility for stack state and error codes.
- This is clearly not done in the example but is highly encouraged at all times, as good practice.
- To take more control means also taking responsibility for stack state and error codes.
sgs_CreateDict( C, NULL, 0 ); sgs_PushString( C, "test" ); sgs_SetIndex( C, sgs_StackItem( C, -2 ), sgs_StackItem( C, -1 ), sgs_StackItem( C, -1 ), 0 ); // result: {test=test}
- It is possible to both read and write from/to sub-items.
- There are 4 sets of functions, each with a different prefix and behavior semantic.
- Get*** functions load the property/index to the specified prepared location.
- Set*** functions save the property/index, taking it from the specified location.
- Push*** functions load the property/index and push it at the top of the stack.
Prefer index access (isprop=0) to property access since the general convention is that indices provide raw access but property access can be augmented with function calls.
sgs_Variable dict, key; sgs_CreateDict( C, &dict, 0 ); sgs_InitString( C, &key, "test" ); sgs_PushInt( C, 5 ): sgs_SetIndex( C, dict, key, sgs_StackItem( C, -1 ), 0 ); // result: {test=5} sgs_PushVariable( C, dict ); sgs_Release( C, &dict ); sgs_Release( C, &key );
- There are pointer equivalents for many API functions. They're usually denoted with an additional uppercase P in the name.
- The situation is a bit different with Index functions: P denotes a pointer argument, I - a stack index/item.
- Both API parts are there to be useful at the right moment. Here's how to decide what to use:
- Use stack-based APIs when you need to...
- deal with function calls - those are stack-only;
- want to have your variables auto-freed on function exit - locally stored variables need to be manually released, stack variables do not;
- Use pointer-based APIs when you need to...
- deal with object interfaces - those are pointers-only;
- permanently store data in a manner that makes it completely unavailable to the script writer;
- name your variables - stack items don't have names and indices might be shifting, making it hard to know what is what;
- Use stack-based APIs when you need to...
sgs_PushInt( C, 3 ); sgs_PushInt( C, 4 ); sgs_PushInt( C, 5 ); sgs_CreateArray( C, NULL, 3 ); sgs_PushNumIndex( C, sgs_StackItem( C, -1 ), 1 ); // pushes [int 4] sgs_PushPath( C, sgs_StackItem( C, -1 ), "i", (sgs_SizeVal) 1 ); // pushes [int 4] too
- There are a few other shortcuts like sgs_PushNumIndex and sgs_PushPath that are worth considering when dealing with sub-items.