SGScript/C++ binding compiler

Table of Contents


SGS/CPP-BC description

This is a compiler that will generate most of the binding code from a bit of markup and additional build configuration. Statistically, the gain is approximately 80% less code to write to connect your C++ code to SGScript.

The compiler can be found at "ext/cppbc/cppbc.sgs". It takes one argument (which should be the header file to process) and it generates one file with the name "cppbc_"+header_file, thus it can be called like this: "sgsvm -p path/to/cppbc.sgs path/to/my_cpp_header.h".

This is a basic example of how things are done with SGS/CPP-BC:

struct UIFrame
{
	typedef sgsHandle< UIFrame > Handle;
	
	SGS_OBJECT;
	
	UIFrame();
	
	SGS_METHOD void event( UIEvent* e );
	SGS_METHOD void render();
	
	SGS_METHOD void doMouseMove( float x, float y );
	SGS_METHOD void doMouseButton( int btn, bool down );
	SGS_METHOD void doKeyPress( int key, bool down );
	
	SGS_IFUNC(GCMARK) int sgs_gcmark( SGS_CTX, sgs_VarObj* obj, int );
	
	SGS_PROPERTY float x;
	SGS_PROPERTY float y;
	SGS_PROPERTY float width;
	SGS_PROPERTY float height;
	SGS_PROPERTY sgsHandle< UIControl > root;
	
	float prevMouseX;
	float prevMouseY;
};

The SGS_OBJECT tag marks the structs/classes that need to have the binding code. SGS_METHOD would then mark methods that require exporting and SGS_PROPERTY generates property exports. For read-only/write-only properties, all you'd need to add is "READ" or "WRITE" after the tag.

sgsVariable and sgsHandle are classes that are used to store SGScript objects. Handles are for storing exported object pointers and variables are for everything. Handles make it easier to use the included objects, thus they are preferred to plain variable containers.

GCMARK handlers are more like the raw API but all that needs to be done in the function is calling gcmark() on each variable or handle. Due to the possibility of having many unknown kinds of containers of variables, it is unlikely that this function could ever be automatically generated, except for the most primitive of cases.


Common usage patterns

declare a variable and bind it

SGS_PROPERTY float x;

bind an inherited variable

SGS_PROPERTY SGS_ALIAS( float x );

bind & declare variable with post-write callback

SGS_PROPERTY_FUNC( READ WRITE WRITE_CALLBACK myWriteCallback ) float x;

bind a fake variable (based on get/set functions)

SGS_PROPERTY_FUNC( READ getX WRITE setX ) SGS_ALIAS( float x );

bind & declare a variable with two different names

SGS_PROPERTY_FUNC( READ WRITE VARNAME sgsName ) float x;

bind an inherited/previously defined variable

SGS_PROPERTY_FUNC( READ WRITE VARNAME sgsName ) SGS_ALIAS( float x );

declare a method and bind it

SGS_METHOD float calc( float x );

declare a vararg method with variable return value count

SGS_METHOD SGS_MULTRET complexFunc();

handle class stub

typedef sgsHandle< struct sgsObj > sgsObjHandle;
struct sgsObj
{
    SGS_OBJECT;
    
    static sgsObjHandle HandleFromPtr( Obj* ); // resolve the link through object's user data pointer or some similar method
    
    sgsObj( Obj* obj ) : m_obj( obj ){}
    ~sgsObj(){ cleanup(); }
    void cleanup() // this is pulled out of constructor in case it might be called by a parent object to invalidate the handle on destruction of the owning system
    {
        if( m_obj )
        {
            // *** free m_obj ***
            m_obj = NULL;
        }
    }
    Obj* m_obj;
    
    // declare additional properties and methods with SGS_PROPERTY(_FUNC) and SGS_METHOD, respectively
    // most properties/methods will most likely have to include a NULL test for m_obj, like this:
    int _getProp(){ return m_obj ? m_obj->GetProp() : 0; }
    void _setProp( int v ){ if( m_obj ) m_obj->SetProp( v ); }
    SGS_PROPERTY_FUNC( READ _getProp WRITE _setProp ) SGS_ALIAS( int prop );
};

data struct stub

struct sgsData : Data
{
    SGS_OBJECT_LITE;
    
    sgsData(){}
    sgsData( const Data& t ) : Data( t ){}
    
    // properties with direct access (non-private)
    SGS_PROPERTY SGS_ALIAS( item1 );
    
    // data struct properties (original type: SubData, wrapped type: sgsSubData)
    sgsSubData _getSubData(){ return subData; }
    void _setSubData( const sgsSubData& sd ){ subData = sd; }
    SGS_PROPERTY_FUNC( READ _getSubData WRITE _setSubData ) SGS_ALIAS( sgsSubData subData );
    
    // properties with method access
    int _getProp(){ return GetProp(); }
    void _setProp( int v ){ SetProp( v ); }
    SGS_PROPERTY_FUNC( READ _getProp WRITE _setProp ) SGS_ALIAS( int prop );
    
    // aliases (second names) for all properties:
    SGS_PROPERTY_FUNC( READ WRITE VARNAME item1alt ) SGS_ALIAS( item1 );
    SGS_PROPERTY_FUNC( READ _getSubData WRITE _setSubData VARNAME subDataAlt ) SGS_ALIAS( sgsSubData subData );
    SGS_PROPERTY_FUNC( READ _getProp WRITE _setProp VARNAME propAlt ) SGS_ALIAS( int prop );
};
SGS_DEFAULT_LITE_OBJECT_INTERFACE( sgsData ); // this line can be replaced with a modified combo of sgs_PushVar/sgs_GetVar/sgs_GetVarP declarations

Tags

SGS_OBJECT

SGS_OBJECT_LITE

Marks the objects/structures for parsing.

SGS_OBJECT_LITE does not add helper variables (sgs_VarObj* m_sgsObject; sgs_Context* C) to the class

SGS_METHOD

Marks the methods that should be made available to the scripting engine.

Syntax: SGS_METHOD <type> <name>(<arguments>);

Alt. syntax (bind without declaration): SGS_METHOD SGS_ALIAS( <type> <name>(<arguments>) );

SGS_PROPERTY

Marks the properties that should be made available to the scripting engine. Currently supports only one property at a time.

Syntax: SGS_PROPERTY [READ|WRITE] <type> <name>;

Alt. syntax (bind without declaration): SGS_PROPERTY [READ|WRITE] SGS_ALIAS( <type> <name> );

Modifiers:

SGS_PROPERTY_FUNC

Marks the properties that should be made available to the scripting engine. Has additional options for reading, writing and callbacks.

Syntax: SGS_PROPERTY_FUNC( <tag-args> ) <type> <name>;

Alt. syntax (bind without declaration): SGS_PROPERTY_FUNC( <tag-args> ) SGS_ALIAS( <type> <name> );

Tag arguments: a space separated list of none or more of the following constructs

SGS_IFUNC

Marks the method as a native object interface function that would override any generated one.

Syntax: SGS_IFUNC( <ifunc-type> ) <type> <name>( sgs_Context*, sgs_VarObj*, int );

"ifunc-type" must be one of SGS_OP_* defines.


Data type handling

template< class T > void sgs_PushVar( SGS_CTX, const T& );

pushes the specified variable on the stack, automatically converting it to the most appropriate SGScript type

template< class T > struct sgs_GetVar { T operator () ( SGS_CTX, int item ); };

takes the specified stack item and converts it to the required type

template< class T > struct sgs_GetVarP { T operator () ( SGS_CTX, sgs_Variable* var ); };

template< class T > struct sgs_GetVarObjP { T* operator () ( SGS_CTX, sgs_Variable* var ); };

takes the specified variable and converts it to the required type


Helper classes & functions

Classes

Functions


sgsHandle [class]

template< class T > class sgsHandle

Variables

Constructors

Methods

Operators


sgsVariable [class]

class sgsVariable

Variables

Constructors

Methods

Operators


sgs_PushHandle [function]

template< class T > inline void sgs_PushHandle( SGS_CTX, const sgsHandle<T>& val )

push the specified class handle on stack


sgs_Push(Lite)Class [function]

template< class T > void sgs_PushClass( SGS_CTX, T* inst )

template< class T > void sgs_PushLiteClass( SGS_CTX, T* inst )

push a new instance of the class on stack

This function should not be used with existing instances, as it would make two or more SGScript objects responsible for the same data. Use sgs_PushVar, sgs_PushHandle or sgs_Push(Lite)ClassFrom with existing instances.


sgs_Push(Lite)ClassIPA [function]

template< class T > T* sgs_PushClassIPA( SGS_CTX )

template< class T > T* sgs_PushLiteClassIPA( SGS_CTX )

allocate a class in-place, push it on the stack

This function should not be used with existing instances, as it would make two or more SGScript objects responsible for the same data. Use sgs_PushVar, sgs_PushHandle or sgs_Push(Lite)ClassFrom with existing instances.


sgs_Push(Lite)ClassFrom [function]

template< class T > T* sgs_PushClassFrom( SGS_CTX, T* inst )

template< class T > T* sgs_PushLiteClassFrom( SGS_CTX, const T* inst )

push a copy of the specified class instance on stack


sgs_InitPushedClass [function]

template< class T> T* sgs_InitPushedClass( T* inst, SGS_CTX )

set context / object pointers to class


SGS_PUSH(LITE)CLASS [function alias]

SGS_PUSHCLASS( C, name, args )

SGS_PUSHLITECLASS( C, name, args )

push a new instance of the specified class, using the specified arguments for constructor

Usage example:

SGS_PUSHCLASS( C, myClass, ( param1, 5.0f ) );