/////////////////////////////////////////////////////////////////////////////
// Name: cpp/overload.cpp
// Purpose: C++ implementation for a function to match a function's
// argument list against a prototype
// Author: Mattia Barbon
// Modified by:
// Created: 07/08/2002
// RCS-ID: $Id: overload.cpp 2953 2010-08-15 14:29:24Z mbarbon $
// Copyright: (c) 2002-2004, 2006-2007, 2010 Mattia Barbon
// Licence: This program is free software; you can redistribute it and/or
// modify it under the same terms as Perl itself
/////////////////////////////////////////////////////////////////////////////
#include "cpp/overload.h"
#if 0
class wxPliArgArray
{
public:
virtual ~wxPliArgArray() {};
virtual SV* operator[]( size_t index ) = 0;
virtual size_t GetCount() const = 0;
};
class wxPliStackArray
{
public:
wxPliStackArray();
private:
SV*** sp;
};
#endif
bool wxPli_match_arguments_offset( pTHX_ const wxPliPrototype& prototype,
int required,
bool allow_more, size_t offset );
bool wxPli_match_arguments_skipfirst( pTHX_ const wxPliPrototype& prototype,
int required /* = -1 */,
bool allow_more /* = false */ )
{
return wxPli_match_arguments_offset( aTHX_ prototype, required,
allow_more, 1 );
}
bool wxPli_match_arguments( pTHX_ const wxPliPrototype& prototype,
int required /* = -1 */,
bool allow_more /* = false */ )
{
return wxPli_match_arguments_offset( aTHX_ prototype, required,
allow_more, 0 );
}
static inline bool IsGV( SV* sv ) { return SvTYPE( sv ) == SVt_PVGV; }
bool wxPli_match_arguments_offset( pTHX_ const wxPliPrototype& prototype,
int required,
bool allow_more, size_t offset )
{
dXSARGS; // restore the mark we implicitly popped in dMARK!
int argc = items - int(offset);
if( required != -1 )
{
if( allow_more && argc < required )
{ PUSHMARK(MARK); return false; }
if( !allow_more && argc != required )
{ PUSHMARK(MARK); return false; }
}
else if( argc < int(prototype.count) )
{ PUSHMARK(MARK); return false; }
size_t max = wxMin( prototype.count, size_t(argc) ) + offset;
for( size_t i = offset; i < max; ++i )
{
const char* p = prototype.args[i - offset];
// everything is a string or a boolean
if( p == wxPliOvlstr ||
p == wxPliOvlbool )
continue;
SV* t = ST(i);
// want a number
if( p == wxPliOvlnum )
{
if( my_looks_like_number( aTHX_ t ) ) continue;
else { PUSHMARK(MARK); return false; }
}
// want an object/package name, accept undef, too
const char* cstr =
p > wxPliOvlzzz ? p :
p == wxPliOvlwpos ? "Wx::Position" :
p == wxPliOvlwpoi ? "Wx::Point" :
p == wxPliOvlwsiz ? "Wx::Size" :
NULL;
if( !IsGV( t )
&& ( !SvOK( t )
|| ( cstr != NULL
&& sv_isobject( t )
&& sv_derived_from( t, CHAR_P cstr )
)
)
)
continue;
// want an array reference
if( p == wxPliOvlarr && wxPli_avref_2_av( t ) ) continue;
// want a wxPoint/wxSize, accept an array reference, too
if( ( p == wxPliOvlwpoi || p == wxPliOvlwsiz || p == wxPliOvlwpos )
&& wxPli_avref_2_av( t ) ) continue;
// want an input/output stream, accept any reference
if( ( p == wxPliOvlwist || p == wxPliOvlwost ) &&
( SvROK( t ) || IsGV( t ) ) ) continue;
// type clash: return false
PUSHMARK(MARK);
return false;
}
PUSHMARK(MARK);
return true;
}
void wxPli_set_ovl_constant( const char* name, const wxPliPrototype* value )
{
dTHX;
char buffer[1024];
strcpy( buffer, "Wx::_" );
strcat( buffer, name );
SV* sv = get_sv( buffer, 1 );
sv_setiv( sv, PTR2IV( value ) );
}
static const char *overload_descriptions[] =
{
NULL, "array", "boolean", "number", "string/scalar", "input stream",
"output stream", "Wx::Point/array", "Wx::Position/array", "Wx::Size/array"
};
void wxPli_overload_error( pTHX_ const char* function,
wxPliPrototype* prototypes[] )
{
dXSARGS; // restore the mark we implicitly popped in dMARK!
SV* message = newSVpv( "Availble methods:\n", 0 );
sv_2mortal( message );
for( int j = 0; prototypes[j]; ++j )
{
wxPliPrototype* p = prototypes[j];
sv_catpv( message, function );
sv_catpv( message, "(" );
for( int i = 0; i < p->count; ++i )
{
if( p->args[i] < wxPliOvlzzz )
sv_catpv( message, overload_descriptions[wxUIntPtr(p->args[i])] );
else
sv_catpv( message, p->args[i] );
if( i != p->count - 1 )
sv_catpv( message, ", " );
}
sv_catpv( message, ")\n" );
}
sv_catpvf( message, "unable to resolve overload for %s(", function );
for( size_t i = 1; i < items; ++i )
{
SV* t = ST(i);
const char* type;
if( !SvOK( t ) )
type = "undef";
else if( sv_isobject( t ) )
type = HvNAME( SvSTASH( SvRV( t ) ) );
else if( SvROK( t ) )
{
SV* r = SvRV( t );
if( SvTYPE( r ) == SVt_PVAV )
type = "array";
else if( SvTYPE( r ) == SVt_PVHV )
type = "hash";
else
type = "reference";
}
else if( IsGV( t ) )
type = "glob/handle";
else if( my_looks_like_number( aTHX_ t ) )
type = "number";
else
type = "scalar";
sv_catpv( message, type );
if( i != items - 1 )
sv_catpv( message, ", " );
}
sv_catpv( message, ")" );
PUSHMARK(MARK); // probably not necessary
require_pv( "Carp.pm" );
const char* argv[2]; argv[0] = SvPV_nolen( message ); argv[1] = NULL;
call_argv( "Carp::croak", G_VOID|G_DISCARD, (char**) argv ); \
}