// Macro definitions for the C++/Perfect binding.

//**************************************************
//* Collection bindings
//**************************************************

// Variable declarations...
#define PV_SET(type_of_set) 						_eSet< type_of_set >
#define PV_BAG(type_of_bag) 						_eBag< type_of_bag >
#define PV_SEQ(type_of_seq) 						_eSeq< type_of_seq >
#define PV_MAP(type_of_map) 						_eMap< type_of_map >
#define PV_PAIR(type_x_of_pair, type_y_of_pair) 	_ePair< type_x_of_pair, type_y_of_pair >
#define PV_TRIPLE(type_x_of_triple, type_y_of_triple, type_z_of_triple) 	_eTriple< type_x_of_triple, type_y_of_triple, type_z_of_triple >
// Operators...
// See 'Miscellaneous bindings'.

//**************************************************
//* Ordering bindings
//**************************************************

// Operations...
#define PO_RANK(first_item, second_item) 	_oRank((first_item), (second_item))
// Rank values...
#define PC_RANKS_BELOW 		_eRank::below
#define PC_RANKS_SAME  		_eRank::same
#define PC_RANKS_ABOVE 		_eRank::above

//**************************************************
//* Regular-type (use-defined-type) bindings
//**************************************************

// Variable declarations...
#define PV_REGTYPE(type_name) 					_eHndl< type_name >
#define PV_SMPLUNION_WITHVOID(type_name) 		_eHndl< type_name >
// Formal parameter declarations...
#define PF_REGTYPE_IN(type_name) 				const type_name*
#define PF_REGTYPE_CH(type_name) 				_eHndl< type_name >&
#define PF_REGTYPELTD_CH(type_name) 			type_name*
// Return type declarations of functions
#define PR_REGTYPE(type_name) 					_eHndl< type_name >		// function (const) return
#define PR_REGTYPE_CH(type_name) 				_eHndl< type_name >&	// selector (non-const) return
// Operations...
#define PO_BUILDREGTYPE(type_name, brktdargs) 	_eHndl< type_name >(new type_name brktdargs )
// Usual instance access operations on regular (handle types) - use the '.._ACCESS_..' version when calling functions or
// schemas that don't change the current object; use the '.._CHANGE_..' version when calling schemas that do modify the
// current object ...
#define PO_ACCESS_REGTYPE(instance) 			(instance).operator*()
#define PO_CHANGE_REGTYPE(instance) 			(instance).Change()
// Special access operators, for use when passing pointers to C++ functions - use spareingly and carefully! ...
#define PO_ACCESS_REGTYPE_NCONST(instance) 		(*(instance).ChangePtr())
#define PO_ACCESS_REGTYPE_NCONST_PTR(instance) 	((instance).ChangePtr())
#define PO_ACCESS_REGTYPE_CONST(instance) 		(*(instance).Ptr())
#define PO_ACCESS_REGTYPE_CONST_PTR(instance) 	((instance).Ptr())
// Union specific operations...
#define PO_BUILDUNION_REG(reg_type_name, data) 			(data)
#define PO_BUILDUNION_REG_SBL(reg_type_name, data) 		(data)
// Miscellaneous operations...
#define PO_REGTYPE_ISVALID(instance) 			((instance).Ptr() != NULL)

//*****************************************************
//* Interface-type (non-handle-type-non-enum) bindings
//*****************************************************

// Variable declarations...
#define PV_IFCTYPE(type_name) 					type_name
// Formal parameter declarations...
#define PF_IFCTYPE_IN(type_name) 				type_name
#define PF_IFCTYPE_CH(type_name) 				type_name&
#define PF_IFCTYPELTD_CH(type_name) 			type_name&
// Return type declarations of functions
#define PR_IFCTYPE(type_name) 					type_name					// function (const) return
#define PR_IFCTYPE_CH(type_name) 				type_name&					// selector (non-const) return
// Operations...
#define PO_BUILDIFCTYPE(type_name, brktdargs) 	type_name brktdargs
// Instance access operations on interface (small-class types)...
#define PO_ACCESS_IFCTYPE(instance) 			instance
#define PO_CHANGE_IFCTYPE(instance) 			instance
// Union specific operations...
#define PO_BUILDUNION_IFC(small_type_name, data) 	_mWrapNonStorable(data, small_type_name)	// small classes
#define PO_BUILDUNION_BASIC(basic_type_name, data)	_mWrapBasic(data, basic_type_name)			// builtin basic types

//*************************************************
//* Interface-type (non-handle-type-enum) bindings
//*************************************************

// Enerated type variable declaration...
#define PV_ENUM(perfect_enum) 							perfect_enum::_eEnum
// Enumeration member access operator...
#define PM_ENUM(perfect_enum, enum_val) 				perfect_enum::enum_val
// Union specific operations...
#define PO_BUILDUNION_ENUM(enum_type_name, data) 		_mWrapEnum(data, enum_type_name)
#define PO_BUILDUNION_ENUM_SBL(enum_type_name, data) 	_mWrapStorableEnum(data, enum_type_name)	// this will only apply to buitin small classes (including strings)
// To-string operation ...
#define PO_ENUM_TOSTRING(perfect_enum, enum_val) 		perfect_enum::_ltoString(enum_val)

//**************************************************
//* String bindings
//**************************************************

// Variable declarations...
#define PV_STRTYPE _rstring
// Formal parameter declarations...
#define PF_STRTYPE_IN _rstring
#define PF_STRTYPE_CH _rstring&
// Operations...
// Build a 'Perfect' string from a C string literal
#define PO_BUILDSTRTYPE_LIT(c_string) 					_mString(c_string)
// Build a 'Perfect' string from a C string variable
#define PO_BUILDSTRTYPE_VAR(c_string) 					_lString(c_string)
// Conversion yielding a C string from a Perfect string valid for use as a function argument only - the memory this allocates
// for the converted string will be destroyed when the expression generated by this macro goes out of scope and for this
// reson, this convertion macro should NOT be used for returning char* pointers from functions. Use the "PO_CONVERTSTR(..)"
// macro instead!!!
#define PO_CONVERTSTR_FORARG(perfect_string) 			(_eCstring(perfect_string).str())
// Conversion operation from Perfect string to C string - This allocates memory (on the 'Perfect' heap) for a copy of the
// string and returns a pointer to it, making it the responsibility of the caller to dispose of the memory when the string
// is no longer required (use the "PO_FREECONVSTR(..)" macro to do this) ...
#define PO_CONVERTSTR(c_string, perfect_string) \
	{ \
		int length = perfect_string._oHash() + 1; \
		c_string = static_cast<char *>(_eMem::alloc(length * sizeof(_eChar))); \
		for (int i = 0; i < static_cast<int>(length) - 1; ++i) { c_string[i] = perfect_string[i]; } \
		c_string[length - 1] = '\0'; \
	}
// Macros to free the memory allocated by a previous "PO_CONVERTSTR(..)" macro call. Not sure which of these versions is the
// best - the 2nd one is more convenient, but will cause problems if the c_string contains non-terminating null characters...
//#define PO_FREECONVSTR(c_string, perfect_string) _eMem::free(c_string, perfect_string._oHash())
#define PO_FREECONVSTR(c_string) 		_eMem::free(c_string, strlen(c_string))
// Union specific operations...
#define PO_BUILDUNION_STR(data) 		_mWrapStorable(data, _rstring)

//**************************************************
//* Heap/ref bindings
//**************************************************

// Variable declarations...
#define PV_HEAPTYPE 					_eHeap
#define PV_REFTYPE(refdObjectType) 		_eRef< refdObjectType >
// Operations...
#define PO_BUILDREF(refdObjectType, refdObjectInstance, heapPtr) 	_eRef< refdObjectType >((refdObjectInstance), (heapPtr))

//**************************************************
//* Union bindings
//**************************************************

#define PV_UNIVUNION _eUnion

//**************************************************
//* Miscellaneous bindings
//**************************************************

// Macros to implement operators - we provide these because some (most) operators are generated as
// functions in the target C++, and thus have special names ...

// UNARY
#define UO_HASH(lhs)				(lhs)._oHash()
#define UO_PLUS(lhs) 				(lhs).operator+()
#define UO_MINUS(lhs) 				(lhs).operator-()
#define UO_LESSTHAN(lhs) 			(lhs)._oPred()
#define UO_GREATERTHAN(lhs) 		(lhs)._oSucc()
// BINARY
#define BO_CARET(lhs, rhs) 			(lhs)._oExp(rhs)
#define BO_STARSTAR(lhs, rhs) 		(lhs)._oStarStar(rhs)
#define BO_PLUSPLUS(lhs, rhs) 		(lhs)._oPlusPlus(rhs)
#define BO_MINUSMINUS(lhs, rhs) 	(lhs)._oMinusMinus(rhs)
#define BO_HASH(lhs, rhs) 			(lhs)._oHash(rhs)
#define BO_PLUS(lhs, rhs) 			(lhs).operator+(rhs)
#define BO_MINUS(lhs, rhs) 			(lhs).operator-(rhs)
#define BO_STAR(lhs, rhs) 			(lhs).operator*(rhs)
#define BO_SLASH(lhs, rhs) 			(lhs)._oDiv(rhs)
#define BO_PERCENT(lhs, rhs) 		(lhs)._oMod(rhs)
#define BO_LESSLESS(lhs, rhs) 		(lhs)._oLessLess(rhs)
#define BO_LESSLESSEQ(lhs, rhs) 	(lhs)._oLessLessEq(rhs)
#define BO_IN(lhs, rhs) 			(rhs)._ovIn(lhs)
#define BO_RANK(lhs, rhs) 			(lhs)._oRank(rhs)
#define BO_DOTDOT(lhs, rhs) 		(lhs)._oRange(rhs)

// Member declaration introduction macros (for readability only)...
#define PM_SCHEMA void
#define PM_FUNCTION

//----------------------------------------------------------------------
// union of string or other small class with anything else
// union of regular class with at least one other class (of any type)
//----------------------------------------------------------------------
// Operators to build universal unions for holding various types (string, regular (handle), [non]storable interface (small) ...
#define PO_BUILDUNION_UNIV_STR(data) 					_mWrapStorable(data, _rstring)
#define PO_BUILDUNION_UNIV_REG(data) 					(static_cast<const _eAny *>(data.Ptr()))
#define PO_BUILDUNION_UNIV_IFC(data, type_of_data) 		_mWrapNonstorable(data, type_of_data)
#define PO_BUILDUNION_UNIV_IFC_SBL(data, type_of_data) 	_mWrapStorable(data, type_of_data)
// Constant representing the void type (for the 'null' value) of the universal union ...
#define PC_UNIVUNION_VOIDVAL 							(_eUnion(_mNullPtr(_eAny))).Ptr()
//----------------------------------------------------------------------
// union of regular class with void
//----------------------------------------------------------------------
#define PO_BUILDUNION_SMPL_REG(data) 					_eUnion((data).Ptr())
#define PT_SMPLUNION_ISVOID(variable_name) 				((variable_name).Ptr() == NULL)
#define PT_SMPLUNION_NOTVOID(variable_name) 			((variable_name).Ptr() != NULL)
#define PC_SMPLUNION_VOIDVAL(type_of_nonvoid_part) 		_mNullPtr(type_of_nonvoid_part)

// Binding for use when we want to call the non-const (change) version of a Perfect selector (remember that 2 C++ functions
// get generated for a proper (ie. not an access) selector, the non-const version having its name pre-fixed with '_s' ...

#define SELECTOR_CALL(selName) 		_s##selName

// Member actual parameter conversion bindings (required due to parameter code-generation rules) ...
// * Use these whenever calling a Perfect function with any non-builtin Perfect type, eg. when calling a function
// * that takes a non-modifiable regular-type (or non-modifiable union) with a regular-type or union we would pass
// * the actual parameter via the 'PA_NONWRTBL_REGTYPE(..)' macro ...
#define PA_NONWRTBL_REGTYPE(param) ((param).Ptr())
#define PA_LTDWRTBL_REGTYPE(param) ((param).ChangePtr())
#define PA_FLYWRTBL_REGTYPE(param) (param)
//
#define PA_NONWRTBL_IFCTYPE(param) (param)
#define PA_LTDWRTBL_IFCTYPE(param) (param)
#define PA_FLYWRTBL_IFCTYPE(param) (param)

/* HELP WITH MACRO NAMES ...
 * PA_ = Perfect actual parameter conversion (use when calling a Perfect function with Perfect data)
 * PC_ = Perfect constant
 * PF_ = Perfect formal-parameter type
 * PM_ = Perfect class member macros
 * PO_ = Perfect operator ???
 * PR_ = Perfect return value generator
 * PT_ = Perfect data-test macro
 * PV_ = Perfect variable declaration
 * BO_ = Perfect binary operator
 * UO_ = Perfect unary operator
*/

// End.
