Files
harbour-core/harbour/source/rtl/classes.c
1999-09-11 09:54:25 +00:00

1057 lines
28 KiB
C

/*
* $Id$
*/
/*
Harbour Project source code
Base-routines for OOPS system
Copyright 1999 Antonio Linares <alinares@fivetech.com>
www - http://www.harbour-project.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version, with one exception:
The exception is that if you link the Harbour Runtime Library (HRL)
and/or the Harbour Virtual Machine (HVM) with other files to produce
an executable, this does not by itself cause the resulting executable
to be covered by the GNU General Public License. Your use of that
executable is in no way restricted on account of linking the HRL
and/or HVM code into it.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
their web site at http://www.gnu.org/).
*/
/* Harbour Project source code
http://www.Harbour-Project.org/
The following functions are Copyright 1999 Eddie Runia <eddie@runia.com>:
partial copyright regarding the following functions :
:CLASSSEL()
__clsDelMsg()
__clsModMsg()
__clsInstSuper()
__cls_CntClsData()
__cls_CntData()
__cls_DecData()
__cls_IncData()
__objClone()
__objHasMsg()
__objSendMsg()
The following functions are Copyright 1999 Victor Szel <info@szelvesz.hu>:
hb___msgEval()
See doc/hdr_tpl.txt, Version 1.2 or later, for licensing terms.
*/
#include "extend.h"
#include "errorapi.h"
#include "itemapi.h"
#include "ctoharb.h"
#include "hboo.ch"
typedef struct
{
void * pMessage; /* pointer to dynamic symbol when they get ready */
PHB_FUNC pFunction;
WORD wData;
WORD wScope;
PHB_ITEM pInitValue;
} METHOD, * PMETHOD;
typedef struct
{
char * szName;
WORD wDatas;
WORD wDataFirst; /* First wData from this class */
PMETHOD pMethods;
WORD wMethods;
WORD wHashKey;
PHB_ITEM pClassDatas; /* Array for ClassDatas */
PHB_ITEM pInlines; /* Array for inline codeblocks */
} CLASS, * PCLASS;
#define BASE_METHODS 200
#define BUCKET 4
#define HASH_KEY ( BASE_METHODS / BUCKET )
static PCLASS s_pClasses = NULL;
static WORD s_wClasses = 0;
static PMETHOD s_pMethod = NULL; /* TOFIX: The object engine is not thread safe because of this. */
static PHB_DYNS s_msgClassName = NULL;
static PHB_DYNS s_msgClassH = NULL;
static PHB_DYNS s_msgEval = NULL;
static PHB_DYNS s_msgClassSel = NULL;
/* All functions contained in classes.c */
static void hb_clsDictRealloc( PCLASS pClass );
static void hb_clsRelease( PCLASS );
void hb_clsReleaseAll( void );
char * hb_objGetClsName( PHB_ITEM pObject );
PHB_FUNC hb_objGetMethod( PHB_ITEM, PHB_SYMB );
ULONG hb_objHasMsg( PHB_ITEM pObject, char *szString );
static HARBOUR hb___msgClsH( void );
static HARBOUR hb___msgClsName( void );
static HARBOUR hb___msgClsSel( void );
static HARBOUR hb___msgSuper( void );
static HARBOUR hb___msgEvalInline( void );
static HARBOUR hb___msgEval( void );
static HARBOUR hb___msgVirtual( void );
static HARBOUR hb___msgGetClsData( void );
static HARBOUR hb___msgSetClsData( void );
static HARBOUR hb___msgGetData( void );
static HARBOUR hb___msgSetData( void );
/* ================================================ */
/*
* hb_clsDictRealloc( PCLASS )
*
* Realloc (widen) class
*/
static void hb_clsDictRealloc( PCLASS pClass )
{
/* TODO: Implement it for very large classes */
if( pClass )
hb_errInternal( 9999, "classes.c hb_clsDictRealloc() not implemented yet", NULL, NULL );
}
/*
* hb_clsRelease( <pClass> )
*
* Release a class from memory
*/
static void hb_clsRelease( PCLASS pClass )
{
WORD wAt;
WORD wLimit = pClass->wHashKey * BUCKET;
PMETHOD pMeth = pClass->pMethods;
for( wAt = 0; wAt < wLimit; wAt++, pMeth++ ) /* Release initializers */
if( pMeth->pInitValue && pMeth->wData > pClass->wDataFirst )
hb_itemRelease( pMeth->pInitValue );
hb_xfree( pClass->szName );
hb_xfree( pClass->pMethods );
hb_itemRelease( pClass->pClassDatas );
hb_itemRelease( pClass->pInlines );
}
/*
* hb_clsReleaseAll()
*
* Release all classes
*/
void hb_clsReleaseAll( void )
{
WORD w;
for( w = 0; w < s_wClasses; w++ )
hb_clsRelease( s_pClasses + w );
if( s_pClasses )
hb_xfree( s_pClasses );
}
/* ================================================ */
/*
* <szName> = hb_objGetClsName( pObject )
*
* Get the class name of an object
*
*/
char * hb_objGetClsName( PHB_ITEM pObject )
{
char * szClassName;
if( IS_ARRAY( pObject ) )
{
if( ! pObject->item.asArray.value->wClass )
szClassName = "ARRAY";
else
szClassName =
( s_pClasses + pObject->item.asArray.value->wClass - 1 )->szName;
}
else /* built in types */
{
switch( pObject->type )
{
case IT_NIL:
szClassName = "NIL";
break;
case IT_STRING:
szClassName = "CHARACTER";
break;
case IT_BLOCK:
szClassName = "BLOCK";
break;
case IT_SYMBOL:
szClassName = "SYMBOL";
break;
case IT_DATE:
szClassName = "DATE";
break;
case IT_INTEGER:
case IT_LONG:
case IT_DOUBLE:
szClassName = "NUMERIC";
break;
case IT_LOGICAL:
szClassName = "LOGICAL";
break;
default:
szClassName = "UNKNOWN";
break;
}
}
return szClassName;
}
/*
* <pFunc> = hb_objGetMethod( <pObject>, <pMessage> )
*
* Internal function to the function pointer of a message of an object
*/
PHB_FUNC hb_objGetMethod( PHB_ITEM pObject, PHB_SYMB pMessage )
{
WORD wClass;
PHB_DYNS pMsg = pMessage->pDynSym;
if( pObject->type == IT_ARRAY )
wClass = pObject->item.asArray.value->wClass;
else
wClass = 0;
if( wClass && wClass <= s_wClasses )
{
PCLASS pClass = &s_pClasses[ wClass - 1 ];
WORD wAt = ( ( ( unsigned ) pMsg ) % pClass->wHashKey ) * BUCKET;
WORD wMask = pClass->wHashKey * BUCKET;
WORD wLimit = wAt ? ( wAt - 1 ) : ( wMask - 1 );
s_pMethod = NULL; /* Current method pointer */
while( wAt != wLimit )
{
if( pClass->pMethods[ wAt ].pMessage == pMsg )
{
s_pMethod = pClass->pMethods + wAt;
return s_pMethod->pFunction;
}
wAt++;
if( wAt == wMask )
wAt = 0;
}
}
if( s_msgClassName == NULL )
{
s_msgClassName = hb_dynsymGet( "CLASSNAME" ); /* Standard messages */
s_msgClassH = hb_dynsymGet( "CLASSH" ); /* Not present in classdef. */
s_msgClassSel = hb_dynsymGet( "CLASSSEL" );
s_msgEval = hb_dynsymGet( "EVAL" );
}
if( pMsg == s_msgClassName )
return hb___msgClsName;
else if( pMsg == s_msgClassH )
return hb___msgClsH;
else if( pMsg == s_msgClassSel )
return hb___msgClsSel;
else if( pMsg == s_msgEval )
return hb___msgEval;
return NULL;
}
/*
* <uPtr> = hb_objHasMsg( <pObject>, <szString> )
*
* Check whether <szString> is an existing message for object.
*
* <uPtr> should be read as a boolean
*/
ULONG hb_objHasMsg( PHB_ITEM pObject, char *szString )
{
PHB_SYMB pMessage = hb_dynsymGet( szString )->pSymbol;
return ( ULONG ) hb_objGetMethod( pObject, pMessage );
} /* Get funcptr of message */
/* ================================================ */
/*
* __clsAddMsg( <hClass>, <cMessage>, <pFunction>, <nType>, [xInit] )
*
* Add a message to the class.
*
* <hClass> Class handle
* <cMessage> Message
* <pFunction> MET_METHOD : Pointer to function
* MET_DATA : Index number in array
* MET_CLASSDATA : Index number in array
* MET_INLINE : Code block
* MET_SUPER : Handle of super class
* <nType> see MET_*
* <xInit> Optional initializer for DATA
*/
HARBOUR HB___CLSADDMSG( void )
{
WORD wClass = hb_parnl( 1 );
if( wClass && wClass <= s_wClasses )
{
PCLASS pClass = &s_pClasses[ wClass - 1 ];
PHB_DYNS pMessage = hb_dynsymGet( hb_parc( 2 ) );
WORD wType = hb_parni( 4 );
WORD wAt = ( ( ( unsigned ) pMessage ) % pClass->wHashKey ) * BUCKET;
WORD wMask = pClass->wHashKey * BUCKET;
PMETHOD pNewMeth;
if( wType == MET_INLINE && hb_param( 3, IT_BLOCK ) == NULL )
{
hb_errRT_BASE( EG_ARG, 3000, NULL, "__CLSADDMSG" );
}
if( pClass->wMethods > ( pClass->wHashKey * BUCKET * 2/3 ) )
hb_clsDictRealloc( pClass );
/* Find either the existing message or an open spot for a new message */
while( pClass->pMethods[ wAt ].pMessage &&
( pClass->pMethods[ wAt ].pMessage != pMessage ) )
wAt = ( wAt == wMask ) ? 0 : wAt + 1;
pNewMeth = pClass->pMethods + wAt;
if( !pNewMeth->pMessage )
{
pNewMeth->pMessage = pMessage;
pClass->wMethods++; /* One more message */
}
switch( wType )
{
case MET_METHOD:
pNewMeth->pFunction = ( PHB_FUNC ) hb_parnl( 3 );
break;
case MET_DATA:
pNewMeth->wData = hb_parnl( 3 );
if( pMessage->pSymbol->szName[ 0 ] == '_' )
pNewMeth->pFunction = hb___msgSetData;
else
{
PHB_ITEM pInit = hb_param( 5, IT_ANY );
pNewMeth->pFunction = hb___msgGetData;
if( pInit && !IS_NIL( pInit )) /* Initializer found */
{
pNewMeth->pInitValue = hb_itemNew( NULL );
hb_itemCopy( pNewMeth->pInitValue, pInit );
}
}
break;
case MET_CLASSDATA:
pNewMeth->wData = hb_parnl( 3 );
if( ( WORD ) hb_arrayLen( pClass->pClassDatas ) < hb_parnl( 3 ) )
hb_arraySize( pClass->pClassDatas, hb_parnl( 3 ) );
if( pMessage->pSymbol->szName[ 0 ] == '_' )
pNewMeth->pFunction = hb___msgSetClsData;
else
pNewMeth->pFunction = hb___msgGetClsData;
break;
case MET_INLINE:
pNewMeth->wData = hb_arrayLen( pClass->pInlines ) + 1;
hb_arraySize( pClass->pInlines, pNewMeth->wData );
hb_arraySet( pClass->pInlines, pNewMeth->wData,
hb_param( 3, IT_BLOCK ) );
pNewMeth->pFunction = hb___msgEvalInline;
break;
case MET_VIRTUAL:
pNewMeth->pFunction = hb___msgVirtual;
break;
case MET_SUPER:
pNewMeth->wData = hb_parnl( 3 );
pNewMeth->pFunction = hb___msgSuper;
break;
default:
hb_errInternal( 9999, "Invalid method type from __clsAddMsg", NULL, NULL );
break;
}
}
}
/*
* <hClass> := __clsNew( <cClassName>, <nDatas>, [hSuper] )
*
* Create a new class
*
* <cClassName> Name of the class
* <nDatas> Number of DATAs in the class
* <hSuper> Optional handle of superclass
*/
HARBOUR HB___CLSNEW( void )
{
WORD wSuper = hb_parni( 3 ); /* Super class present */
PCLASS pNewCls;
if( s_pClasses )
s_pClasses = ( PCLASS ) hb_xrealloc( s_pClasses,
sizeof( CLASS ) * ( s_wClasses + 1 ) );
else
s_pClasses = ( PCLASS ) hb_xgrab( sizeof( CLASS ) );
pNewCls = s_pClasses + s_wClasses;
pNewCls->szName = ( char * ) hb_xgrab( hb_parclen( 1 ) + 1 );
strcpy( pNewCls->szName, hb_parc( 1 ) );
if( wSuper )
{
PCLASS pSprCls = s_pClasses + wSuper - 1;
WORD wSize;
pNewCls->wDataFirst = pSprCls->wDatas;
pNewCls->wDatas = pSprCls->wDatas + hb_parni( 2 );
pNewCls->wMethods = pSprCls->wMethods;
pNewCls->pClassDatas = hb_arrayClone( pSprCls->pClassDatas );
pNewCls->pInlines = hb_arrayClone( pSprCls->pInlines );
pNewCls->wHashKey = pSprCls->wHashKey;
wSize = pSprCls->wHashKey * BUCKET * sizeof( METHOD );
pNewCls->pMethods = ( PMETHOD ) hb_xgrab( wSize );
memcpy( pNewCls->pMethods, pSprCls->pMethods, wSize );
} /* Copy all super methods */
else
{
pNewCls->wDatas = hb_parni( 2 );
pNewCls->wDataFirst = 0;
pNewCls->pMethods = ( PMETHOD ) hb_xgrab( BASE_METHODS * sizeof( METHOD ) );
pNewCls->wMethods = 0;
pNewCls->wHashKey = HASH_KEY; /* BUCKET = 4 repetitions */
pNewCls->pClassDatas = hb_itemArrayNew( 0 );
pNewCls->pInlines = hb_itemArrayNew( 0 );
memset( pNewCls->pMethods, 0, BASE_METHODS * sizeof( METHOD ) );
}
hb_retni( ++s_wClasses );
}
/*
* __clsDelMsg( <oObj>, <cMessage> )
*
* Delete message (only for INLINE and METHOD)
*
* <oObj> Object
* <cMessage> Message
*/
HARBOUR HB___CLSDELMSG( void )
{
WORD wClass = hb_parni( 1 );
PHB_ITEM pString = hb_param( 2, IT_STRING );
if( wClass && wClass <= s_wClasses && pString )
{
PCLASS pClass = s_pClasses + wClass - 1;
PHB_SYMB pMessage = hb_dynsymGet( pString->item.asString.value )->pSymbol;
PHB_DYNS pMsg = pMessage->pDynSym;
WORD wAt = ( ( ( unsigned ) pMsg ) % pClass->wHashKey ) * BUCKET;
WORD wMask = pClass->wHashKey * BUCKET;
WORD wLimit = wAt ? ( wAt - 1 ) : ( wMask - 1 );
while( ( wAt != wLimit ) &&
( pClass->pMethods[ wAt ].pMessage &&
( pClass->pMethods[ wAt ].pMessage != pMsg ) ) )
{
wAt++;
if( wAt == wMask )
wAt = 0;
}
if( wAt != wLimit )
{ /* Requested method found */
PHB_FUNC pFunc = pClass->pMethods[ wAt ].pFunction;
if( pFunc == hb___msgEvalInline ) /* INLINE method deleted */
{
hb_arrayDel( pClass->pInlines, pClass->pMethods[ wAt ].wData );
/* Delete INLINE block */
}
/* Move messages */
while( pClass->pMethods[ wAt ].pMessage && wAt != wLimit )
{
memcpy( pClass->pMethods + wAt,
pClass->pMethods + ( ( wAt == wMask ) ? 0 : wAt + 1 ),
sizeof( METHOD ) );
wAt++;
if( wAt == wMask )
wAt = 0;
}
memset( pClass->pMethods + wAt, 0, sizeof( METHOD ) );
pClass->wMethods--; /* Decrease number messages */
}
}
}
/*
* <oNewObject> := __clsInst( <hClass> )
*
* Create a new object from class definition <hClass>
*/
HARBOUR HB___CLSINST( void )
{
WORD wClass = hb_parni( 1 );
if( wClass <= s_wClasses )
{
PCLASS pClass = s_pClasses + ( wClass - 1 );
WORD wAt;
WORD wLimit = pClass->wHashKey * BUCKET;
PMETHOD pMeth = pClass->pMethods; /* Initialize DATA */
hb_arrayNew( &stack.Return, pClass->wDatas );
stack.Return.item.asArray.value->wClass = wClass;
for( wAt = 0; wAt < wLimit; wAt++, pMeth++ )
if( pMeth->pInitValue )
hb_itemArrayPut( &stack.Return, pMeth->wData, pMeth->pInitValue );
}
}
/*
* __clsModMsg( <oObj>, <cMessage>, <pFunc> )
*
* Modify message (only for INLINE and METHOD)
*/
HARBOUR HB___CLSMODMSG( void )
{
WORD wClass = hb_parni( 1 );
PHB_ITEM pString = hb_param( 2, IT_STRING );
if( wClass && wClass <= s_wClasses && pString )
{
PCLASS pClass = s_pClasses + wClass - 1;
PHB_SYMB pMessage = hb_dynsymGet( pString->item.asString.value )->pSymbol;
PHB_DYNS pMsg = pMessage->pDynSym;
WORD wAt = ( ( ( unsigned ) pMsg ) % pClass->wHashKey ) * BUCKET;
WORD wMask = pClass->wHashKey * BUCKET;
WORD wLimit = wAt ? ( wAt - 1 ) : ( wMask - 1 );
while( ( wAt != wLimit ) &&
( pClass->pMethods[ wAt ].pMessage &&
( pClass->pMethods[ wAt ].pMessage != pMsg ) ) )
{
wAt++;
if( wAt == wMask )
wAt = 0;
}
if( wAt != wLimit )
{ /* Requested method found */
PHB_FUNC pFunc = pClass->pMethods[ wAt ].pFunction;
if( pFunc == hb___msgEvalInline ) /* INLINE method changed */
{
PHB_ITEM pBlock = hb_param( 3, IT_BLOCK );
if( pBlock == NULL )
hb_errRT_BASE( EG_ARG, 3000, NULL, "__CLSMODMSG" );
else
hb_arraySet( pClass->pInlines, pClass->pMethods[ wAt ].wData, pBlock );
}
else if( ( pFunc == hb___msgSetData ) || ( pFunc == hb___msgGetData ) )
{ /* Not allowed for DATA */
hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a DATA item", "__CLSMODMSG" );
}
else /* Modify METHOD */
pClass->pMethods[ wAt ].pFunction = ( PHB_FUNC ) hb_parnl( 3 );
}
}
}
/*
* <cClassName> := ClassName( <hClass> )
*
* Returns class name of <hClass>
*/
HARBOUR HB___OBJGETCLSNAME( void )
{
PHB_ITEM pObject = hb_param( 0, IT_OBJECT );
WORD wClass;
if( pObject && pObject->item.asArray.value->wClass )
{
wClass = pObject->item.asArray.value->wClass;
hb_retc( s_pClasses[ wClass - 1 ].szName );
}
else
{
wClass = hb_parni( 1 );
if( wClass <= s_wClasses )
hb_retc( s_pClasses[ wClass - 1 ].szName );
else
hb_retc( "" );
}
}
/*
* <lRet> := __objHasMsg( <oObj>, <cSymbol> )
*
* Is <cSymbol> a valid message for the <oObj>
*/
HARBOUR HB___OBJHASMSG( void )
{
PHB_ITEM pObject = hb_param( 1, IT_OBJECT );
PHB_ITEM pString = hb_param( 2, IT_STRING );
if( pObject && pString )
hb_retl( hb_objHasMsg( pObject, pString->item.asString.value ) != 0 );
else
hb_errRT_BASE( EG_ARG, 3000, NULL, "__OBJHASMSG" );
}
/*
* <oNew> := __objClone( <oOld> )
*
* Clone an object. Note the similarity with aClone ;-)
*/
HARBOUR HB___OBJCLONE( void )
{
PHB_ITEM pSrcObject = hb_param( 1, IT_OBJECT );
if( pSrcObject )
{
PHB_ITEM pDstObject = hb_arrayClone( pSrcObject );
hb_itemCopy( &stack.Return, pDstObject );
hb_itemRelease( pDstObject );
}
else
hb_errRT_BASE( EG_ARG, 3001, NULL, "__OBJCLONE" );
}
/*
* <xRet> = __objSendMsg( <oObj>, <cSymbol>, <xArg,..>
*
* Send a message to an object
*/
HARBOUR HB___OBJSENDMSG( void )
{
PHB_ITEM pObject = hb_param( 1, IT_OBJECT );
PHB_ITEM pMessage = hb_param( 2, IT_STRING );
if( pMessage && pObject ) /* Object & message passed */
{
WORD w;
hb_vmPush( pObject ); /* Push object */
hb_vmMessage( hb_dynsymGet( pMessage->item.asString.value )->pSymbol );
/* Push char symbol as message */
for( w = 3; w <= hb_pcount(); w++ ) /* Push arguments on stack */
hb_vmPush( hb_param( w, IT_ANY ) );
hb_vmDo( hb_pcount()-2 ); /* Execute message */
}
else
hb_errRT_BASE( EG_ARG, 3000, NULL, "__OBJSENDMSG" );
}
/*
* <hClass> := __clsInstSuper( <cName> )
*
* Instance super class and return class handle
*/
HARBOUR HB___CLSINSTSUPER( void )
{
PHB_ITEM pString = hb_param( 1, IT_STRING );
BOOL bFound = FALSE;
if( pString )
{
PHB_DYNS pDynSym = hb_dynsymFind( pString->item.asString.value );
if( pDynSym ) /* Find function */
{
WORD w;
hb_vmPushSymbol( pDynSym->pSymbol ); /* Push function name */
hb_vmPushNil();
hb_vmFunction( 0 ); /* Execute super class */
if( !IS_OBJECT( &stack.Return ) )
{
hb_errRT_BASE( EG_ARG, 3002, "Super class does not return an object", "__CLSINSTSUPER" );
}
for( w = 0; !bFound && w < s_wClasses; w++ )
{ /* Locate the entry */
if( !hb_stricmp( pString->item.asString.value, s_pClasses[ w ].szName ) )
{
hb_retni( w + 1 ); /* Entry + 1 = hb___msgClsH */
bFound = TRUE;
}
}
}
else
hb_errRT_BASE( EG_ARG, 3003, "Cannot find super class", "__CLSINSTSUPER" );
}
if( !bFound )
hb_retni( 0 );
}
/*
* <nSeq> = __cls_CntClsData( <hClass> )
*
* Return number of class datas
*/
HARBOUR HB___CLS_CNTCLSDATA( void )
{
WORD wClass = hb_parnl( 1 );
if( wClass )
{
PCLASS pClass = &s_pClasses[ wClass - 1 ];
hb_retni( hb_arrayLen( pClass->pClassDatas ) );
}
}
/*
* <nSeq> = __cls_CntData( <hClass> )
*
* Return number of datas
*/
HARBOUR HB___CLS_CNTDATA( void )
{
WORD wClass = hb_parnl( 1 );
if( wClass )
hb_retni( s_pClasses[ wClass - 1 ].wDatas );
}
/*
* <nSeq> = __cls_DecData( <hClass> )
*
* Return number of datas and decrease
*/
HARBOUR HB___CLS_DECDATA( void )
{
WORD wClass = hb_parnl( 1 );
if( wClass )
hb_retni( s_pClasses[ wClass - 1 ].wDatas-- );
}
/*
* <nSeq> = __cls_IncData( <hClass> )
*
* Return number of datas and decrease
*/
HARBOUR HB___CLS_INCDATA( void )
{
WORD wClass = hb_parnl( 1 );
if( wClass )
hb_retni( ++s_pClasses[ wClass - 1 ].wDatas );
}
/* ================================================ */
/*
* <hClass> := <obj>:ClassH()
*
* Returns class handle of <obj>
*/
static HARBOUR hb___msgClsH( void )
{
if( IS_ARRAY( stack.pBase + 1 ) )
hb_retni( ( stack.pBase + 1 )->item.asArray.value->wClass );
else
hb_retni( 0 );
}
/*
* <cClassName> := <obj>:ClassName()
*
* Return class name of <obj>. Can also be used for all types.
*/
static HARBOUR hb___msgClsName( void )
{
PHB_ITEM pItemRef;
if( IS_BYREF( stack.pBase + 1 ) ) /* Variables by reference */
pItemRef = hb_itemUnRef( stack.pBase + 1 );
else
pItemRef = stack.pBase + 1;
hb_retc( hb_objGetClsName( pItemRef ) );
}
/*
* <aMessages> := <obj>:ClassSel()
*
* Returns all the messages in <obj>
*/
static HARBOUR hb___msgClsSel( void )
{
WORD wClass = IS_ARRAY( stack.pBase + 1 ) ?
( stack.pBase + 1 )->item.asArray.value->wClass : 0;
/* Get class word */
PHB_ITEM pReturn = hb_itemNew( NULL );
if( ( ! wClass ) && IS_BYREF( stack.pBase + 1 ) )
{ /* Variables by reference */
PHB_ITEM pItemRef = hb_itemUnRef( stack.pBase + 1 );
if( IS_ARRAY( pItemRef ) )
wClass = pItemRef->item.asArray.value->wClass;
}
if( wClass && wClass <= s_wClasses )
{
PCLASS pClass = &s_pClasses[ wClass - 1 ];
WORD wLimit = pClass->wHashKey * BUCKET; /* Number of Hash keys */
WORD wPos = 0;
WORD wAt;
hb_itemRelease( pReturn );
pReturn = hb_itemArrayNew( pClass->wMethods );
/* Create a transfer array */
for( wAt = 0; wAt < wLimit ; wAt++ )
{
PHB_DYNS pMessage = ( PHB_DYNS ) pClass->pMethods[ wAt ].pMessage;
if( pMessage ) /* Hash Entry used ? */
{
PHB_ITEM pItem = hb_itemPutC( NULL, pMessage->pSymbol->szName );
/* Add to array */
hb_itemArrayPut( pReturn, ++wPos, pItem );
hb_itemRelease( pItem );
}
}
}
hb_itemReturn( pReturn );
hb_itemRelease( pReturn );
}
/*
* __msgEvalInline()
*
* Internal function executed for inline methods
*/
static HARBOUR hb___msgEvalInline( void )
{
HB_ITEM block;
WORD wClass = ( stack.pBase + 1 )->item.asArray.value->wClass;
WORD w;
hb_arrayGet( s_pClasses[ wClass - 1 ].pInlines, s_pMethod->wData, &block );
hb_vmPushSymbol( &symEval );
hb_vmPush( &block );
hb_vmPush( stack.pBase + 1 ); /* Push self */
for( w = 1; w <= hb_pcount(); w++ )
hb_vmPush( hb_param( w, IT_ANY ) );
hb_vmDo( hb_pcount() + 1 ); /* Self is also an argument */
hb_itemClear( &block ); /* Release block */
}
/*
* __msgEval()
*
* Internal function for the internal EVAL method.
*/
static HARBOUR hb___msgEval( void )
{
if( IS_BLOCK( stack.pBase + 1 ) )
{
USHORT uiParam;
hb_vmPushSymbol( &symEval );
hb_vmPush( stack.pBase + 1 ); /* Push block */
for( uiParam = 1; uiParam <= hb_pcount(); uiParam++ )
hb_vmPush( hb_param( uiParam, IT_ANY ) );
hb_vmDo( hb_pcount() ); /* Self is also an argument */
}
else
{
PHB_ITEM pResult = hb_errRT_BASE_Subst( EG_NOMETHOD, 1004, NULL, "EVAL" );
if( pResult )
{
hb_itemReturn( pResult );
hb_itemRelease( pResult );
}
}
}
/*
* __msgGetClsData()
*
* Internal function to return a CLASSDATA
*/
static HARBOUR hb___msgGetClsData( void )
{
WORD wClass = ( stack.pBase + 1 )->item.asArray.value->wClass;
if( wClass && wClass <= s_wClasses )
hb_arrayGet( s_pClasses[ wClass - 1 ].pClassDatas, s_pMethod->wData, &stack.Return );
}
/*
* __msgGetData()
*
* Internal function to return a DATA
*/
static HARBOUR hb___msgGetData( void )
{
PHB_ITEM pObject = stack.pBase + 1;
WORD wIndex = s_pMethod->wData;
if( wIndex > ( WORD ) hb_arrayLen( pObject ) )
/* Resize needed */
hb_arraySize( pObject, wIndex ); /* Make large enough */
hb_arrayGet( pObject, wIndex, &stack.Return );
}
/*
* __msgSuper()
*
* Internal function to cast to a super method
*/
static HARBOUR hb___msgSuper( void )
{
PHB_ITEM pObject = stack.pBase + 1;
PHB_ITEM pSuper = ( PHB_ITEM ) hb_xgrab( sizeof( HB_ITEM ) );
PBASEARRAY pNewBase = ( PBASEARRAY ) hb_xgrab( sizeof( BASEARRAY ) );
WORD wSuperCls = s_pMethod->wData; /* Get handle of superclass */
memcpy( pSuper, pObject, sizeof( HB_ITEM ) );
/* Allocate new structures */
memcpy( pNewBase, pObject->item.asArray.value, sizeof( BASEARRAY ) );
pSuper->item.asArray.value = pNewBase;
pNewBase->wClass = wSuperCls;
pNewBase->wHolders = 1; /* New item is returned */
pNewBase->bSuperCast = TRUE; /* Do not dispose pItems !! */
/* A bit dirty, but KISS. */
hb_itemCopy( &stack.Return, pSuper );
hb_itemRelease( pSuper );
}
/*
* __msgSetClsData()
*
* Internal function to set a CLASSDATA
*/
static HARBOUR hb___msgSetClsData( void )
{
WORD wClass = ( stack.pBase + 1 )->item.asArray.value->wClass;
PHB_ITEM pReturn = stack.pBase + 2;
if( wClass && wClass <= s_wClasses )
{
hb_arraySet( s_pClasses[ wClass - 1 ].pClassDatas,
s_pMethod->wData, pReturn );
hb_itemCopy( &stack.Return, pReturn );
}
}
/*
* __msgSetData()
*
* Internal function to set a DATA
*/
static HARBOUR hb___msgSetData( void )
{
PHB_ITEM pObject = stack.pBase + 1;
PHB_ITEM pReturn = stack.pBase + 2;
WORD wIndex = s_pMethod->wData;
/* Resize needed ? */
if( wIndex > ( WORD ) hb_arrayLen( pObject ) )
/* Make large enough */
hb_arraySize( pObject, wIndex );
hb_arraySet( pObject, wIndex, pReturn );
hb_itemCopy( &stack.Return, pReturn );
}
/* No comment :-) */
static HARBOUR hb___msgVirtual( void )
{
hb_ret();
}