#!/usr/bin/perl -w
use strict;

#
# Description:
#	C++ preprocessor to add the 'delegate' keyword.
#
# Author:
#	Phillip Pearson <pp@myelin.co.nz>
#
# Version:
#	Revision 1 - 2001-02-21
#
# Usage:
#	Pipe a C++ header file into this script and compile
#	the output.
#
#	in your Makefile:
#		perl -w cpppp.pl < blah.hpp > blah.h
#	and in your program:
#		#include "blah.h"
#
# Delegate syntax:
#
#	delegate type ident( args );
#
#	e.g. delegate int FooDelegate( char* pokwer, int blah );
#
#	This will expand out into an interface called FooDelegate,
#	a class template called FooDelegate_Delegate, and a helper
#	function called new_FooDelegate().
#
#	Pass a delegate as a FooDelegate*, and make them using
#	new_FooDelegate().  new_FooDelegate() takes a pointer to
#	your object and a pointer to the method you want to call back.
#
# License:
#
#	You may distribute this file under the same terms as
#	Perl itself.
#


while (<STDIN>) {
	s/\r//; s/\n//;
	
	/\s*delegate\s+(.*)\s+(.*?)\s*\(\s*(.*?)\s*\)\s*\;/ && do {
		my $line = $_;
		my $del_type = $1;
		my $del_ident = $2;
		my $del_vars = $3;
		
		# figure out var names so we can implement Call
		my $del_var_names = "<don't know var names>";
		do {
			# get var definitions
			my @vars = split(/\,/, $del_vars);
			for (@vars) {
				# trim spaces
				s/^\s*(.*?)\s*$/$1/;
				# figure out var name
				s/.*\s//g;
				s/\[.*?\]//g;
			}
			# squish it all together
			$del_var_names = join(", ", @vars);
		};
		
		# capitalise identifier
		my $del_ident_caps = $del_ident;
		$del_ident_caps =~ tr/a-z/A-Z/;

		
		print <<END;
// Automatically-generated delegate

// Type:           $del_type
// Identifier:     $del_ident
// Variable defs:  $del_vars
// Variable names: $del_var_names

// From definition:
// 	$line

// Interface definition for delegate '$del_ident'
class ${del_ident}
{
public:
	virtual $del_type Call( $del_vars ) = 0;
};

// Delegate object
template< class T >
class ${del_ident}_Delegate : public $del_ident
{
private: 
	T* _that; 
	void (T::*_func)( int a, int b, int c ); 
  
public: 
	${del_ident}_Delegate( T* that, void (T::*func)( $del_vars ) )
	{
		_that = that;
		_func = func;
	} 
	
	virtual void Call( $del_vars ) {
		(_that->*_func)( $del_var_names );
	} 
};

template< class T >
inline ${del_ident}_Delegate<T>* new_${del_ident}( T* that, void (T::*func)( $del_vars ) )
{
	return new MyCallback_Delegate<T>( that, func );
}

END
		
	} or print "$_\n";
}
