Reflection.cpp

// Reflection.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2009

@import "Ceda/cxPython/cxPython.h"
@import "Ceda/cxObject/Object.h"
@import "Ceda/cxObject/WCSpace.h"
#include "Ceda/cxUtils/TracerUtils.h"

///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Illustrates how python can directly access reflection information about classes, interfaces
etc.
*/
namespace Reflection1
{
    void Run()
    {
        ceda::TraceGroup g("Reflection example 1");

        ceda::CSpaceCreator cspace;
        ceda::CSpaceLock lock;

        PyRun_SimpleString(
            @strx
            (
                def GetBit(value,bitpos):
                    return (value & (1 << bitpos)) != 0

                assert(ceda.EReflectedClassBits.RCF_CLASS == 0)
                assert(ceda.EReflectedClassBits.RCF_PURE_MODEL == 1)
                assert(ceda.EReflectedClassBits.RCF_HAS_EMBEDDED_MODEL == 2)
                assert(ceda.EReflectedClassBits.RCF_REFERENCES_MODEL == 3)
                assert(ceda.EReflectedClassBits.RCF_ADT == 4)
                assert(ceda.EReflectedClassBits.RCF_ALLOW_PASS_BY_VALUE == 5)
                assert(ceda.EReflectedClassBits.RCF_ALLOW_RETURN_BY_VALUE == 6)
                assert(ceda.EReflectedClassBits.RCF_REPLICATE_ON_DEMAND == 7)

                def PrintEnumInfo(e,indent):
                    print ' '*indent + '$enum ' + str(e.GetName())
                    print ' '*indent + '{'
                    for i in range(0,e.GetCount()):
                        s = ' '*indent + '    '
                        if not e.GetEnable(i):
                            s += '-'
                        s += str(e.GetString(i)) + ' = ' + str(e.GetValue(i))
                        print(s) 
                    print ' '*indent + '}'

                def GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,fn):
                    proto = ''
                    if rbcRet.IsNull():
                        proto = 'void'
                    else:
                        proto = str(rbcRet)
                    proto += ' ' + str(fn.GetName()) + '('
                    for j in range(0,fn.GetNumArgs()):
                        a = fn.GetArg(j)
                        rbc = getArgByteCode(a)
                        proto += str(rbc) + ' ' + str(a.GetName())
                        if j != fn.GetNumArgs()-1:
                            proto += ','
                    proto += ')'
                    if isMethod and fn.IsConst():
                        proto += ' const'
                    return proto

                # Returns a string representation of the prototype of an interface method
                def GetInterfaceMethodPrototype(ri,m):
                    rbcRet = ceda.GetInterfaceMethodReturnTypeByteCode(ri,m)
                    def getArgByteCode(a):
                        return ceda.GetInterfaceMethodArgByteCode(ri,a)
                    isMethod = 1
                    return GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,m)

                # Returns a string representation of the prototype of a class method
                def GetClassMethodPrototype(rc,m):
                    rbcRet = ceda.GetClassMethodReturnTypeByteCode(rc,m)
                    def getArgByteCode(a):
                        return ceda.GetClassMethodArgByteCode(rc,a)
                    isMethod = 1
                    return GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,m)

                def GetGlobalFunctionPrototype(gf):
                    rbcRet = ceda.GetGlobalFunctionReturnTypeByteCode(gf)
                    def getArgByteCode(a):
                        return ceda.GetGlobalFunctionArgByteCode(gf,a)
                    isMethod = 0
                    return GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,gf)
                    
                def GetFunctorPrototype(f):
                    rbcRet = ceda.GetFunctorReturnTypeByteCode(f)
                    def getArgByteCode(a):
                        return ceda.GetFunctorArgByteCode(f,a)
                    isMethod = 0
                    return GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,f)
                    
                def PrintGlobalFunctionInfo(gf,indent):
                    print ' '*indent + '$function ' + GetGlobalFunctionPrototype(gf)

                def PrintFunctorInfo(f,indent):
                    print ' '*indent + '$functor ' + GetFunctorPrototype(f)
                
                def PrintGlobalVariableInfo(gv,indent):
                    rbc = ceda.GetGlobalVariableByteCode(gv)
                    print ' '*indent + '$var ' + str(rbc) + ' ' + str(gv.GetName())

                def PrintTypedefInfo(t,indent):
                    rbc = ceda.GetTypeDefByteCode(t)
                    print ' '*indent + '$typedef ' + str(rbc) + ' ' + str(t.GetName())

                def PrintInterfaceInfo(ri,indent):
                    print ' '*indent + '$interface ' + str(ri.GetName())
                    print ' '*indent + '{'
                    for i in range(0,ri.GetNumMethods()):
                        m = ri.GetMethod(i)
                        print ' '*indent + '    ' + GetInterfaceMethodPrototype(ri,m)
                    print ' '*indent + '}'

                def PrintVariantInfo(rv,indent):
                    print ' '*indent + '$variant ' + str(rv.GetName())
                    print ' '*indent + '{'
                    for i in range(0,rv.GetNumFields()):
                        f = rv.GetField(i)
                        rbc = ceda.GetVariantFieldByteCode(rv,f)
                        s = '[' + str(f.GetOffset()) + ']'
                        s += '    '
                        s += str(rbc) + ' ' + str(f.GetName())
                        print ' '*indent + '    ' + s
                    print ' '*indent + '}'

                    
                def PrintClassInfo(c,indent):
                    assert(c.IsStruct() == (not GetBit(c.GetFlags(), ceda.EReflectedClassBits.RCF_CLASS)))
                    assert(c.IsPureModel() == GetBit(c.GetFlags(), ceda.EReflectedClassBits.RCF_PURE_MODEL))
                    assert(c.HasEmbeddedModel() == GetBit(c.GetFlags(), ceda.EReflectedClassBits.RCF_HAS_EMBEDDED_MODEL))
                    assert(c.ReferencesModel() == GetBit(c.GetFlags(), ceda.EReflectedClassBits.RCF_REFERENCES_MODEL))
                    assert(c.IsAdt() == GetBit(c.GetFlags(), ceda.EReflectedClassBits.RCF_ADT))
                    assert(c.ReplicateOnDemand() == GetBit(c.GetFlags(), ceda.EReflectedClassBits.RCF_REPLICATE_ON_DEMAND))

                    print ' '*indent + '$' + str(c.GetKeyWord()) + ' ' + str(c.GetName())
                    print ' '*indent + '{'
                    indent += 4
                    #print ' '*indent + 'Flags = ' + str(c.GetFlags())
                    print ' '*indent + 'Size = ' + str(c.GetSize()) + ' bytes'
                    print ' '*indent + 'CanCreate = ' + str(c.CanCreate())

                    if c.GetNumModelFields() > 0:
                        print ' '*indent + 'model'
                        print ' '*indent + '{'
                        for i in range(0,c.GetNumModelFields()):
                            f = c.GetModelField(i)
                            rbc = ceda.GetModelFieldByteCode(c,f)
                            s = '[' + str(f.GetOffset()) + ']'
                            s += '    '
                            s += str(rbc) + ' ' + str(f.GetName()) + '    '
                            s += '[' + str(f.GetRsn1()) + ',' + str(f.GetRsn2()) + ')'
                            if not f.Present():
                                s += '*'
                            print ' '*indent + '    ' + s
                        print ' '*indent + '}'

                    if c.GetNumFields() > 0:
                        print ' '*indent + 'fields'
                        print ' '*indent + '{'
                        for i in range(0,c.GetNumFields()):
                            f = c.GetField(i)
                            rbc = ceda.GetFieldByteCode(c,f)
                            s = '[' + str(f.GetOffset()) + ']'
                            s += '    '
                            s += str(rbc) + ' ' + str(f.GetName())
                            print ' '*indent + '    ' + s
                        print ' '*indent + '}'  

                    if c.GetNumMethods() > 0:
                        print ' '*indent + 'methods'
                        print ' '*indent + '{'
                        for i in range(0,c.GetNumMethods()):
                            m = c.GetMethod(i)
                            print ' '*indent + '    ' + GetClassMethodPrototype(c,m)
                        print ' '*indent + '}'  

                    if c.GetNumIndirectInterfaces() > 0:
                        print ' '*indent + 'indirect interfaces'
                        print ' '*indent + '{'
                        for i in range(0,c.GetNumIndirectInterfaces()):
                            nm = c.GetInterfaceName(i)
                            print ' '*indent + '    ' + str(nm)
                        print ' '*indent + '}'  

                    if c.GetNumDirectInterfaces() > 0:
                        print ' '*indent + 'direct interfaces'
                        print ' '*indent + '{'
                        for i in range(c.GetNumIndirectInterfaces(),c.GetNumInterfaces()):
                            nm = c.GetInterfaceName(i)
                            print ' '*indent + '    ' + str(nm)
                        print ' '*indent + '}'  
                    
                    indent -= 4
                    print ' '*indent + '}'

                def PrintNameSpaceElement(nse,indent):
                    tp = nse.GetType()
                    if tp == ceda.ENSType.NST_Interface:
                        PrintInterfaceInfo(nse.AsInterface(),indent)
                    elif tp == ceda.ENSType.NST_Class:
                        PrintClassInfo(nse.AsClass(),indent)
                    elif tp == ceda.ENSType.NST_GlobalFunction:
                        PrintGlobalFunctionInfo(nse.AsGlobalFunction(),indent)
                    elif tp == ceda.ENSType.NST_GlobalVariable:
                        PrintGlobalVariableInfo(nse.AsGlobalVariable(),indent)
                    elif tp == ceda.ENSType.NST_Typedef:
                        PrintTypedefInfo(nse.AsTypedef(),indent)
                    elif tp == ceda.ENSType.NST_Enum:
                        PrintEnumInfo(nse.AsEnum(),indent)
                    elif tp == ceda.ENSType.NST_Functor:
                        PrintFunctorInfo(nse.AsFunctor(),indent)
                    elif tp == ceda.ENSType.NST_Variant:
                        PrintVariantInfo(nse.AsVariant(),indent)
                    else:
                        print 'unrecognised namespace element type ' + str(tp)
                        Assert(False)

                def DumpNameSpace(ns,indent):
                    # Show all elements in namespace ns
                    i = ns.GetElementIterator()
                    while not i.AtEnd():
                        nse = i.GetElement()
                        tp = nse.GetType()
                        PrintNameSpaceElement(nse,indent)
                        i.Next()
                    i.Close()

                    # Recurse into child namespaces
                    i = ns.GetChildNameSpaceIterator()
                    while not i.AtEnd():
                        print ' '*indent + 'namespace ' + str(i.GetName())
                        DumpNameSpace(i.GetNameSpace(),indent+4)
                        i.Next()
                    i.Close()
                
                DumpNameSpace(rootnamespace.pizza, 0)
            ));
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Illustrates how python can recurse down through the namespaces of reflected classes, interfaces
etc.
*/

namespace NamespaceDemo
{
    void Run()
    {
		ceda::TraceGroup g("Namespace example");

        PyRun_SimpleString(
            @strx
            (
                # Return the object associated with the given NameSpaceElement
                def ConvertNameSpaceElement(nse):
                    tp = nse.GetType()
                    if tp == ceda.ENSType.NST_Interface:
                        return nse.AsInterface()
                    elif tp == ceda.ENSType.NST_Class:
                        return nse.AsClass()
                    elif tp == ceda.ENSType.NST_GlobalFunction:
                        return nse.AsGlobalFunction()
                    elif tp == ceda.ENSType.NST_GlobalVariable:
                        return nse.AsGlobalVariable()
                    elif tp == ceda.ENSType.NST_Typedef:
                        return nse.AsTypedef()
                    elif tp == ceda.ENSType.NST_Enum:
                        return nse.AsEnum()
                    elif tp == ceda.ENSType.NST_Functor:
                        return nse.AsFunctor()
                    elif tp == ceda.ENSType.NST_Variant:
                        return nse.AsVariant()
                    else:
                        Assert(False)
                
                def DumpNameSpace(ns,indent):
                    # Show all elements in namespace ns
                    i = ns.GetElementIterator()
                    while not i.AtEnd():
                        nse = i.GetElement()
                        tp = nse.GetType()
                        print ConvertNameSpaceElement(nse)
                        if tp == ceda.ENSType.NST_Class:
                            print 'Class name = ' + `nse.AsClass().GetName()`
                        #print ' '*indent + str(ceda.ENSType.GetString(tp))[4:] + ' ' + `i.GetName()`
                        print ' '*indent + str(ceda.ENSType.GetString(tp)) + ' ' + `i.GetName()`
                        i.Next()
                    i.Close()

                    # Recurse into child namespaces
                    i = ns.GetChildNameSpaceIterator()
                    while not i.AtEnd():
                        print ' '*indent + 'Namespace ' + `i.GetName()`
                        DumpNameSpace(i.GetNameSpace(),indent+4)
                        i.Next()
                    i.Close()
                
                DumpNameSpace(rootnamespace,0)
                print 'End of NamespaceDemo example'
            ));
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
namespace Reflection
{
    void Run()
    {
        Reflection1::Run();
        //NamespaceDemo::Run();
    }
}