Well looking at how we did things in the Squirrel we use I see in squirrel.h:
1.)
// C::B patch: Comment out Unicode stuff
//#ifdef _UNICODE
//#define SQUNICODE
//#endif
...and 2.)
// C::B patch: Comment out typedef
//typedef unsigned short wchar_t;
What happens if you do the same in Squirrel 3.x.x?
(We also don't compile with SQUNICODE btw...)
Well I just tried with your example, and if I exchange lines 109-122 with:
// C::B patch: Unicode stuff only if not omitted
#if !defined(SQUNICODE) && defined(_UNICODE) && !defined(NO_SQUNICODE)
#define SQUNICODE
#endif
#ifdef SQUNICODE
#if (defined(_MSC_VER) && _MSC_VER >= 1400) // 1400 = VS8
#if !defined(_NATIVE_WCHAR_T_DEFINED) // this is if the compiler considers wchar_t as native type
#define wchar_t unsigned short
#endif
// C::B patch: typedef only for non-GCC
#elif !defined(__GNUC__) // wchar_t is already defined in GCC
typedef unsigned short wchar_t;
#endif
...and then within your sqtest sample:
static void printfunc(HSQUIRRELVM v,const SQChar *s,...)
{
va_list vl;
va_start(vl, s);
#ifdef SQUNICODE
vwprintf(s, vl);
#else
vprintf(s, vl);
#endif
va_end(vl);
}
...and all references in sqRat to sq_throwerror with something like:
if(SQ_FAILED(sq_get(vm, 1))) { // Lookup the proper overload
return sq_throwerror(vm, _SC("No overload matching this argument list found"));// How to best appropriately error?
}
...it works fine here, when compiling with SQUNICODE enabled.
It seems sqrat was never tried with unicode, too - but these simple changes should do it.
Can you provide a test case of all three solutions? For the enums: What do we do currently with SQPlus (I cannot have a look atm...)?
What we currently do with SQPlus is a macro (one invocation per enum type) that expands to code like this:
namespace SqPlus \
{ \
inline void Push(HSQUIRRELVM v,T value) { sq_pushinteger(v,value); } \
inline bool Match(TypeWrapper<T>, HSQUIRRELVM v, int idx) { return sq_gettype(v,idx) == OT_INTEGER; } \
inline T Get(TypeWrapper<T>,HSQUIRRELVM v,int idx) { SQInteger i; SQPLUS_CHECK_GET(sq_getinteger(v,idx,&i)); return (T)i; } \
}
Which, if I understand correctly, provides a kind of "getter function" for the compile-time constant, which I guess is evaluated at runtime by the SQPlus layer... though I don't quite get how it matches enum names...
The "maintain separately " solution would look something like this:
// File printing_types.h
enum PrintColourMode
{
pcmBlackAndWhite,
pcmColourOnWhite,
pcmInvertColours,
pcmAsIs
};
// File bindings/sc_base_types.h
Sqrat::ConstTable().Enum(_SC("PrintColourMode"), Sqrat::Enumeration() .Const(_SC("pcmBlackAndWhite"), pcmBlackAndWhite)
Sqrat::ConstTable().Enum(_SC("PrintColourMode"), Sqrat::Enumeration() .Const(_SC("pcmColourOnWhite"), pcmColourOnWhite)
Sqrat::ConstTable().Enum(_SC("PrintColourMode"), Sqrat::Enumeration() .Const(_SC("pcmInvertColours"), pcmInvertColours)
Sqrat::ConstTable().Enum(_SC("PrintColourMode"), Sqrat::Enumeration() .Const(_SC("pcmAsIs"), pcmAsIs)
If someone adds an enumeration on one end and forgets the other, it all crashes and burns. Also, you have to do this once for every single enum value in every single enum type.
... and the X-Macro solution would look something like this:
// File print_colour_mode.h
X(pcmBlackAndWhite, = 5)
X(pcmColourOnWhite, )
X(pcmInvertColours, )
X(pcmAsIs, )
// File printing_types.h
#define END END2(__LINE__, __COUNTER__) /* need this to get rid of the last comma */
#define END2(a,b) END3(a,b)
#define END3(a,b) _##a##b##_
#define X(a, b) a b,
enum PrintColourMode
{
#include "print_colour_mode.h"
END
};
#undef X
// File sc_base_types.h
#define X(a, b) .Const(_SC(#a), a)
void bind_enums()
{
Sqrat::ConstTable().Enum
(
_SC("PrintColourMode"), Sqrat::Enumeration()
#include "print_colour_mode.h"
);
}
#undef X
This is not really C++ any more, but surprisingly it works...
The code would be somewhat less ugly if enums always started at zero and were contiguous ... but alas, life is not fair...