瀏覽代碼

Add reflection support to mx2!

Mark Sibly 9 年之前
父節點
當前提交
a43630c255

+ 4 - 1
modules/monkey/monkey.monkey2

@@ -11,6 +11,7 @@ Namespace monkey
 #Import "gc.monkey2"
 
 #Import "native/bbtypes.cpp"
+#Import "native/bbinit.cpp"
 #Import "native/bbassert.cpp"
 #Import "native/bbmemory.cpp"
 #Import "native/bbstring.cpp"
@@ -20,4 +21,6 @@ Namespace monkey
 #Import "native/bbgc.cpp"
 #Import "native/bbobject.cpp"
 #Import "native/bbdebug.cpp"
-#Import "native/bbinit.cpp"
+#Import "native/bbvariant.cpp"
+#Import "native/bbtypeinfo.cpp"
+#Import "native/bbdeclinfo.cpp"

+ 2 - 2
modules/monkey/native/bbarray.h

@@ -41,7 +41,7 @@ template<class T,int D> struct bbArray{
 	bbArray(){
 	}
 		
-	template<class...Args> bbArray( Args...args ){
+	template<class...Args> explicit bbArray( Args...args ){
 		
 		int sizes[]{ args... };
 		for( int i=1;i<D;++i ) sizes[i]*=sizes[i-1];
@@ -55,7 +55,7 @@ template<class T,int D> struct bbArray{
 		bbGC::endCtor( _rep );
 	}
 		
-	template<class...Args> bbArray( std::initializer_list<T> init,Args...args ){
+	template<class...Args> explicit bbArray( std::initializer_list<T> init,Args...args ){
 		
 		int sizes[]{ args... };
 		for( int i=1;i<D;++i ) sizes[i]*=sizes[i-1];

+ 10 - 10
modules/monkey/native/bbdebug.h

@@ -25,16 +25,16 @@ inline bbString bbDBType( bbString *p ){ return "String"; }
 
 inline bbString bbDBValue( void *p ){ return "?????"; }
 inline bbString bbDBValue( bbBool *p ){ return *p ? "True" : "False"; }
-inline bbString bbDBValue( bbByte *p ){ return *p; }
-inline bbString bbDBValue( bbUByte *p ){ return *p; }
-inline bbString bbDBValue( bbShort *p ){ return *p; }
-inline bbString bbDBValue( bbUShort *p ){ return *p; }
-inline bbString bbDBValue( bbInt *p ){ return *p; }
-inline bbString bbDBValue( bbUInt *p ){ return *p; }
-inline bbString bbDBValue( bbLong *p ){ return *p; }
-inline bbString bbDBValue( bbULong *p ){ return *p; }
-inline bbString bbDBValue( bbFloat *p ){ return *p; }
-inline bbString bbDBValue( bbDouble *p ){ return *p; }
+inline bbString bbDBValue( bbByte *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbUByte *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbShort *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbUShort *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbInt *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbUInt *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbLong *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbULong *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbFloat *p ){ return bbString(*p); }
+inline bbString bbDBValue( bbDouble *p ){ return bbString(*p); }
 extern bbString bbDBValue( bbString *p );
 
 template<class T> bbString bbDBType(){

+ 22 - 0
modules/monkey/native/bbdeclinfo.cpp

@@ -0,0 +1,22 @@
+
+#include "bbdeclinfo.h"
+
+// ***** bbDeclInfo ****
+
+bbString bbDeclInfo::toString(){
+	return kind+" "+name+":"+(type ? type->name : "?????");
+}
+
+bbVariant bbDeclInfo::get( bbVariant instance ){
+	bbRuntimeError( "Decl is not gettable" );
+	return {};
+}
+	
+void bbDeclInfo::set( bbVariant instance,bbVariant value ){
+	bbRuntimeError( "Decl is not settable" );
+}
+	
+bbVariant bbDeclInfo::invoke( bbVariant instance,bbArray<bbVariant> params ){
+	bbRuntimeError( "Decl is not invokable" );
+	return {};
+}

+ 299 - 0
modules/monkey/native/bbdeclinfo.h

@@ -0,0 +1,299 @@
+
+#ifndef BB_DECLINFO_H
+#define BB_DECLINFO_H
+
+#include "bbtypeinfo.h"
+#include "bbvariant.h"
+
+struct bbDeclInfo{
+
+	bbString name;
+	bbString kind;
+	bbTypeInfo *type;
+	
+	bbString getName(){
+		return name;
+	}
+	
+	bbString getKind(){
+		return kind;
+	}
+	
+	bbTypeInfo *getType(){
+		return type;
+	}
+	
+	virtual bbString toString();
+
+	virtual bbVariant get( bbVariant instance );
+	
+	virtual void set( bbVariant instance,bbVariant value );
+	
+	virtual bbVariant invoke( bbVariant instance,bbArray<bbVariant> params );
+};
+
+// ***** Global *****
+//
+template<class T> struct bbGlobalDeclInfo : public bbDeclInfo{
+
+	T *ptr;
+	
+	bbGlobalDeclInfo( bbString name,T *ptr ):ptr( ptr ){
+		this->name=name;
+		this->kind="Global";
+		this->type=bbGetType<T>();
+	}
+	
+	bbVariant get( bbVariant instance ){
+	
+		return bbVariant( *ptr );
+	}
+	
+	void set( bbVariant instance,bbVariant value ){
+	
+		*ptr=value.get<T>();
+	}
+};
+
+template<class T> struct bbGlobalVarDeclInfo : public bbDeclInfo{
+
+	bbGCVar<T> *ptr;
+	
+	bbGlobalVarDeclInfo( bbString name,bbGCVar<T> *ptr ):ptr( ptr ){
+		this->name=name;
+		this->kind="Global";
+		this->type=bbGetType<T>();
+	}
+	
+	bbVariant get( bbVariant instance ){
+	
+		return bbVariant( ptr->get() );
+	}
+	
+	void set( bbVariant instance,bbVariant value ){
+	
+		*ptr=value.get<T*>();
+	}
+};
+
+
+template<class T> bbDeclInfo *bbGlobalDecl( bbString name,T *ptr ){
+
+	return new bbGlobalDeclInfo<T>( name,ptr );
+}
+
+template<class T> bbDeclInfo *bbGlobalDecl( bbString name,bbGCVar<T> *ptr ){
+
+	return new bbGlobalVarDeclInfo<T>( name,ptr );
+}
+
+// ***** Field *****
+//
+template<class C,class T> struct bbFieldDeclInfo : public bbDeclInfo{
+
+	T C::*ptr;
+	
+	bbFieldDeclInfo( bbString name,T C::*ptr ):ptr( ptr ){
+		this->name=name;
+		this->kind="Field";
+		this->type=bbGetType<T>();
+	}
+	
+	bbVariant get( bbVariant instance ){
+	
+		C *p=instance.get<C*>();
+		
+		return bbVariant( p->*ptr );
+	}
+	
+	void set( bbVariant instance,bbVariant value ){
+	
+		C *p=instance.get<C*>();
+		
+		p->*ptr=value.get<T>();
+	}
+};
+
+template<class C,class T> struct bbFieldVarDeclInfo : public bbDeclInfo{
+
+	bbGCVar<T> C::*ptr;
+	
+	bbFieldVarDeclInfo( bbString name,bbGCVar<T> C::*ptr ):ptr( ptr ){
+		this->name=name;
+		this->kind="Field";
+		this->type=bbGetType<T*>();
+	}
+	
+	bbVariant get( bbVariant instance ){
+	
+		C *p=instance.get<C*>();
+		
+		return bbVariant( (p->*ptr).get() );
+	}
+	
+	void set( bbVariant instance,bbVariant value ){
+	
+		C *p=instance.get<C*>();
+		
+		p->*ptr=value.get<T*>();
+	}
+};
+
+template<class C,class T> bbDeclInfo *bbFieldDecl( bbString name,T C::*ptr ){
+
+	return new bbFieldDeclInfo<C,T>( name,ptr );
+}
+
+template<class C,class T> bbDeclInfo *bbFieldDecl( bbString name,bbGCVar<T> C::*ptr ){
+
+	return new bbFieldVarDeclInfo<C,T>( name,ptr );
+}
+
+// ***** Constructor *****
+//
+template<class C,class...A> struct bbCtorDeclInfo : public bbDeclInfo{
+
+	bbCtorDeclInfo(){
+		this->name="New";
+		this->kind="Constructor";
+		this->type=bbGetType<bbFunction<void(A...)>>();
+	}
+	
+	template<int...I> C *invoke( bbArray<bbVariant> params,detail::seq<I...> ){
+	
+		return bbGCNew<C>( params[I].get<A>()... );
+	}
+	
+	bbVariant invoke( bbVariant instance,bbArray<bbVariant> params ){
+	
+		return bbVariant( invoke( params,detail::gen_seq<sizeof...(A)>{} ) );
+	}
+};
+
+template<class C,class...A> bbDeclInfo *bbCtorDecl(){
+
+	return new bbCtorDeclInfo<C,A...>();
+}
+
+// ***** Method *****
+//
+template<class C,class R,class...A> struct bbMethodDeclInfo : public bbDeclInfo{
+
+	R (C::*ptr)(A...);
+	
+	bbMethodDeclInfo( bbString name,R (C::*ptr)(A...) ):ptr( ptr ){
+		this->name=name;
+		this->kind="Method";
+		this->type=bbGetType<bbFunction<R(A...)>>();
+	}
+	
+	template<int...I> R invoke( C *p,bbArray<bbVariant> params,detail::seq<I...> ){
+	
+		return (p->*ptr)( params[I].get<A>()... );
+	}
+	
+	bbVariant invoke( bbVariant instance,bbArray<bbVariant> params ){
+	
+		C *p=instance.get<C*>();
+		
+		return bbVariant( invoke( p,params,detail::gen_seq<sizeof...(A)>{} ) );
+	}
+};
+
+template<class C,class...A> struct bbMethodDeclInfo<C,void,A...> : public bbDeclInfo{
+
+	typedef void R;
+
+	R (C::*ptr)(A...);
+	
+	bbMethodDeclInfo( bbString name,R (C::*ptr)(A...) ):ptr( ptr ){
+		this->name=name;
+		this->kind="Method";
+		this->type=bbGetType<bbFunction<R(A...)>>();
+	}
+	
+	template<int...I> R invoke( C *p,bbArray<bbVariant> params,detail::seq<I...> ){
+	
+		return (p->*ptr)( params[I].get<A>()... );
+	}
+
+	bbVariant invoke( bbVariant instance,bbArray<bbVariant> params ){
+	
+		C *p=instance.get<C*>();
+		
+		invoke( p,params,detail::gen_seq<sizeof...(A)>{} );
+		
+		return {};
+	}
+};
+
+template<class C,class R,class...A> bbDeclInfo *bbMethodDecl( bbString name,R (C::*ptr)(A...) ){
+
+	return new bbMethodDeclInfo<C,R,A...>( name,ptr );
+}
+
+// ***** Function *****
+//
+template<class R,class...A> struct bbFunctionDeclInfo : public bbDeclInfo{
+
+	R (*ptr)(A...);
+	
+	bbFunctionDeclInfo( bbString name,R (*ptr)(A...) ):ptr( ptr ){
+		this->name=name;
+		this->kind="Function";
+		this->type=bbGetType<bbFunction<R(A...)>>();
+	}
+	
+	template<int...I> R invoke( bbArray<bbVariant> params,detail::seq<I...> ){
+	
+		return (*ptr)( params[I].get<A>()... );
+	}
+	
+	bbVariant invoke( bbVariant instance,bbArray<bbVariant> params ){
+	
+		return bbVariant( invoke( params,detail::gen_seq<sizeof...(A)>{} ) );
+	}
+};
+
+template<class...A> struct bbFunctionDeclInfo<void,A...> : public bbDeclInfo{
+
+	typedef void R;
+
+	R (*ptr)(A...);
+	
+	bbFunctionDeclInfo( bbString name,R (*ptr)(A...) ):ptr( ptr ){
+		this->name=name;
+		this->kind="Function";
+		this->type=bbGetType<bbFunction<R(A...)>>();
+	}
+	
+	template<int...I> R invoke( bbArray<bbVariant> params,detail::seq<I...> ){
+	
+		return (*ptr)( params[I].get<A>()... );
+	}
+	
+	bbVariant invoke( bbVariant instance,bbArray<bbVariant> params ){
+	
+		invoke( params,detail::gen_seq<sizeof...(A)>{} );
+		
+		return {};
+	}
+};
+
+template<class R,class...A> bbDeclInfo *bbFunctionDecl( bbString name,R (*ptr)(A...) ){
+
+	return new bbFunctionDeclInfo<R,A...>( name,ptr );
+}
+
+template<class...Ds> bbDeclInfo **bbMembers( Ds...ds ){
+
+	int n=sizeof...(Ds);
+	bbDeclInfo *ts[]={ ds... };
+	bbDeclInfo **ps=new bbDeclInfo*[n+1];
+	for( int i=0;i<n;++i ) ps[i]=ts[i];
+	ps[n]=0;
+	
+	return ps;
+}
+
+#endif

+ 4 - 0
modules/monkey/native/bbfunction.h

@@ -250,6 +250,10 @@ template<class C,class R,class...A> bbFunction<R(A...)> bbMethod( const bbGCVar<
 	return bbFunction<R(A...)>( c.get(),p );
 }
 
+template<class R,class...A> bbFunction<R(A...)> bbMakefunc( R(*p)(A...) ){
+	return bbFunction<R(A...)>( p );
+}
+
 template<class R,class...A> void bbGCMark( const bbFunction<R(A...)> &t ){
 	t._rep->gcMark();
 }

+ 5 - 30
modules/monkey/native/bbgc.h

@@ -258,38 +258,13 @@ template<class T> struct bbGCVar{
 	}
 };
 
-/*
-template<class T> struct bbGCRootVar : public bbGCVar<T>,public bbGCRoot{
-	
-	using bbGCVar<T>::operator=;
-
-	bbGCRootVar(){
-	}
-	
-	bbGCRootVar( T *p ){
-		this->_ptr=p;
-		enqueue();
-	}
-	
-	bbGCRootVar( const bbGCVar<T> &p ){
-		this->_ptr=p._ptr;
-		enqueue();
-	}
-
-	void gcMark(){
-		bbGC::enqueue( dynamic_cast<bbGCNode*>( _ptr ) );
-	}
-};
-*/
-
-template<class T> void bbGCMark( const T &t ){}
-
-template<class T> void bbGCMark( const bbGCVar<T> &v ){
-	bbGC::enqueue( dynamic_cast<bbGCNode*>( v._ptr ) );
+template<class T> void bbGCMark( T const& ){
 }
+//inline void bbGCMark(...){
+//}
 
-template<class T> void bbGCMarkPtr( T *p ){
-	bbGC::enqueue( dynamic_cast<bbGCNode*>( p ) );
+template<class T> void bbGCMark( const bbGCVar<T> &v ){
+	bbGCMark( v._ptr );
 }
 
 #endif

+ 4 - 1
modules/monkey/native/bbmonkey.h

@@ -3,6 +3,7 @@
 #define BB_MONKEY_H
 
 #include "bbstd.h"
+#include "bbinit.h"
 #include "bbtypes.h"
 #include "bbassert.h"
 #include "bbmemory.h"
@@ -12,7 +13,9 @@
 #include "bbarray.h"
 #include "bbfunction.h"
 #include "bbobject.h"
-#include "bbinit.h"
+#include "bbvariant.h"
+#include "bbtypeinfo.h"
+#include "bbdeclinfo.h"
 
 extern int bb_argc;
 extern char **bb_argv;

+ 12 - 0
modules/monkey/native/bbobject.h

@@ -8,12 +8,18 @@
 
 struct bbObject : public bbGCNode{
 
+	typedef bbObject *bb_object_type;
+
 	bbObject(){
 		bbGC::beginCtor( this );
 	}
 	
 	virtual ~bbObject(){
 	}
+
+	//implemented in bbtypeinfo.h
+	//	
+	virtual bbTypeInfo *typeof()const;
 	
 	virtual const char *typeName()const{
 		return "monkey.Object";
@@ -35,6 +41,8 @@ struct bbThrowable : public bbObject{
 
 struct bbInterface{
 
+	typedef bbInterface *bb_object_type;
+
 	virtual ~bbInterface(){
 	}
 };
@@ -50,6 +58,10 @@ template<class T,class...A> T *bbGCNew( A...a ){
 	return p;
 }
 
+template<class T,class R=typename T::bb_object_type> void bbGCMark( T *p ){
+	bbGC::enqueue( dynamic_cast<bbObject*>( p ) );
+}
+
 template<class T,class C> T bb_object_cast( const bbGCVar<C> &p ){
 	return dynamic_cast<T>( p._ptr );
 }

+ 1 - 1
modules/monkey/native/bbstring.cpp

@@ -195,7 +195,7 @@ const char *bbString::c_str()const{
 }
 
 bbString bbString::fromChar( int chr ){
-	wchar_t chrs[]={ chr };
+	wchar_t chrs[]={ wchar_t(chr) };
 	return bbString( chrs,1 );
 }
 

+ 7 - 10
modules/monkey/native/bbstring.h

@@ -67,7 +67,7 @@ class bbString{
 	bbString():_rep( &_nullRep ){
 	}
 	
-	bbString( const bbString &str ):_rep( str._rep ){
+	bbString( const bbString &s ):_rep( s._rep ){
 		retain();
 	}
 	
@@ -87,37 +87,37 @@ class bbString{
 	bbString( const wchar_t *data,int length ):_rep( Rep::create( data,length ) ){
 	}
 
-	bbString( bbInt n ){
+	explicit bbString( bbInt n ){
 		char data[64];
 		sprintf( data,"%i",n );
 		_rep=Rep::create( data );
 	}
 	
-	bbString( bbUInt n ){
+	explicit bbString( bbUInt n ){
 		char data[64];
 		sprintf( data,"%u",n );
 		_rep=Rep::create( data );
 	}
 	
-	bbString( bbLong n ){
+	explicit bbString( bbLong n ){
 		char data[64];
 		sprintf( data,"%lld",n );
 		_rep=Rep::create( data );
 	}
 	
-	bbString( bbULong n ){
+	explicit bbString( bbULong n ){
 		char data[64];
 		sprintf( data,"%llu",n );
 		_rep=Rep::create( data );
 	}
 	
-	bbString( float n ){
+	explicit bbString( float n ){
 		char data[64];
 		sprintf( data,"%.9g",n );
 		_rep=Rep::create( data );
 	}
 	
-	bbString( double n ){
+	explicit bbString( double n ){
 		char data[64];
 		sprintf( data,"%.17g",n );
 		_rep=Rep::create( data );
@@ -519,7 +519,4 @@ inline bbString BB_T( const char *p ){
 	return bbString::fromCString( p );
 }
 
-inline void bbGCMark( const bbString &t ){
-}
-
 #endif

+ 243 - 0
modules/monkey/native/bbtypeinfo.cpp

@@ -0,0 +1,243 @@
+
+#include "bbtypeinfo.h"
+#include "bbdeclinfo.h"
+
+namespace{
+
+	bbClassTypeInfo *_classes;
+}
+
+// ***** bbTypeInfo *****
+
+bbString bbTypeInfo::toString(){
+	return name;
+}
+
+bbTypeInfo *bbTypeInfo::pointeeType(){
+	bbRuntimeError( "Type '"+name+"' is not a pointer type" );
+	return 0; 
+}
+	
+bbTypeInfo *bbTypeInfo::elementType(){
+	bbRuntimeError( "Type '"+name+"' is not an array type" );
+	return 0;
+}
+	
+int bbTypeInfo::arrayRank(){
+	bbRuntimeError( "Type '"+name+"' is not an array type" );
+	return 0;
+}
+	
+bbTypeInfo *bbTypeInfo::returnType(){
+	bbRuntimeError( "Type '"+name+"' is not a function type" );
+	return 0; 
+}
+	
+bbArray<bbTypeInfo*> bbTypeInfo::paramTypes(){
+	bbRuntimeError( "Type '"+name+"' is not a function type" );
+	return {};
+}
+	
+bbTypeInfo *bbTypeInfo::superType(){
+	bbRuntimeError( "Type '"+name+"' is not a class type" );
+	return 0;
+}
+	
+bbBool bbTypeInfo::extendsType( bbTypeInfo *type ){
+	bbRuntimeError( "Type '"+name+"' is not a class type" );
+	return false;
+}
+	
+bbArray<bbDeclInfo*> bbTypeInfo::getDecls(){
+	bbRuntimeError( "Type '"+name+"' is not a class type" );
+	return {};
+}
+
+bbDeclInfo *bbTypeInfo::getDecl( bbString name ){
+
+	bbArray<bbDeclInfo*> decls=getDecls();
+	bbDeclInfo *found=0;
+
+	for( int i=0;i<decls.length();++i ){
+		bbDeclInfo *decl=decls[i];
+		if( decl->name!=name ) continue;
+		if( found ) return 0;
+		found=decl;
+	}
+
+	return found;
+}
+
+bbArray<bbDeclInfo*> bbTypeInfo::getDecls( bbString name ){
+
+	bbArray<bbDeclInfo*> decls=getDecls();
+
+	int n=0;
+	for( int i=0;i<decls.length();++i ){
+		if( decls[i]->name==name ) ++n;
+	}
+	if( !n ) return {};
+	
+	bbArray<bbDeclInfo*> rdecls;
+	
+	int j=0;
+	for( int i=0;i<decls.length();++i ){
+		if( decls[i]->name==name) rdecls[j++]=decls[i];
+	}
+	return rdecls;
+}
+
+bbDeclInfo *bbTypeInfo::getDecl( bbString name,bbTypeInfo *type ){
+
+	bbArray<bbDeclInfo*> decls=getDecls();
+
+	for( int i=0;i<decls.length();++i ){
+		bbDeclInfo *decl=decls[i];
+		if( decl->name==name && decl->type==type ) return decl;
+	}
+	
+	return 0;
+}
+
+bbTypeInfo *bbTypeInfo::getType( bbString cname ){
+
+	for( bbClassTypeInfo *c=_classes;c;c=c->_succ ){
+		if( c->name==cname ) return c;
+	}
+	
+	return 0;
+}
+
+bbArray<bbTypeInfo*> bbTypeInfo::getTypes(){
+
+	int n=0;
+	for( bbClassTypeInfo *c=_classes;c;c=c->_succ ) ++n;
+	
+	bbArray<bbTypeInfo*> types( n );
+	
+	int i=0;
+	for( bbClassTypeInfo *c=_classes;c;c=c->_succ ) types[i++]=c;
+	
+	return types;
+}
+
+
+// ***** bbUnknownTypeInfo *****
+
+bbUnknownTypeInfo::bbUnknownTypeInfo(){
+	this->name=BB_T("Unknown@")+bbString( bbLong( this ) );
+	this->kind="Unknown";
+}
+
+
+// ***** bbVoidTypeInfo *****
+
+bbVoidTypeInfo bbVoidTypeInfo::instance;
+
+bbVoidTypeInfo::bbVoidTypeInfo(){
+	this->name="Void";
+	this->kind="Void";
+}
+
+
+// ***** bbObjectTypeInfo *****
+
+bbObjectTypeInfo bbObjectTypeInfo::instance;
+
+bbObjectTypeInfo::bbObjectTypeInfo(){
+	this->name="Object";
+	this->kind="Class";
+}
+	
+bbTypeInfo *bbObjectTypeInfo::superType(){
+	return 0;
+}
+	
+bbBool bbObjectTypeInfo::extendsType( bbTypeInfo *type ){
+	return type==&instance;
+}
+	
+bbArray<bbDeclInfo*> bbObjectTypeInfo::getDecls(){
+	return {};
+}
+
+bbTypeInfo *bbObject::typeof()const{
+
+	return &bbObjectTypeInfo::instance;
+}
+
+
+// ***** bbPrimTypeInfo *****
+
+bbPrimTypeInfo::bbPrimTypeInfo( bbString name ){
+	this->name=name;
+	this->kind="Primitive";
+}
+
+
+// ***** bbClassDecls *****
+
+bbClassDecls::bbClassDecls( bbClassTypeInfo *classType ){
+	_succ=classType->_decls;
+	classType->_decls=this;
+}
+
+bbDeclInfo **bbClassDecls::decls(){
+
+	if( !_decls ){
+		_decls=initDecls();
+		bbDeclInfo **p=_decls;
+		while( *p ) ++p;
+		_numDecls=p-_decls;
+	}
+	
+	return _decls;
+}
+
+int bbClassDecls::numDecls(){
+	if( !_decls ) decls();
+	return _numDecls;
+}
+
+// ***** bbClassTypeInfo *****
+
+bbClassTypeInfo::bbClassTypeInfo( bbString name,bbString kind ){
+//	printf( "ClassTypeInfo:%s\n",name.c_str() );
+	this->name=name;
+	this->kind=kind;
+	_succ=_classes;
+	_classes=this;
+}
+
+bbBool bbClassTypeInfo::extendsType( bbTypeInfo *type ){
+	if( type==this ) return true;
+	if( bbTypeInfo *super=superType() ) return super->extendsType( type );
+	return false;
+}
+
+bbArray<bbDeclInfo*> bbClassTypeInfo::getDecls(){
+
+	int n=0;
+	for( bbClassDecls *m=_decls;m;m=m->_succ ) n+=m->numDecls();
+	
+	bbArray<bbDeclInfo*> rdecls( n );
+	
+	int i=0;
+	for( bbClassDecls *m=_decls;m;m=m->_succ ){
+		bbDeclInfo **decls=m->decls();
+		int n=m->numDecls();
+		for( int j=0;j<n;++j ) rdecls[i++]=decls[j];
+	}
+	
+	return rdecls;
+}
+
+bbClassTypeInfo *bbClassTypeInfo::getNamespace( bbString name ){
+
+	for( bbClassTypeInfo *nmspace=_classes;nmspace;nmspace=nmspace->_succ ){
+		if( nmspace->name==name ) return nmspace;
+	}
+	
+	bbClassTypeInfo *nmspace=new bbClassTypeInfo( name,"Namespace" );
+	return nmspace;
+}

+ 255 - 0
modules/monkey/native/bbtypeinfo.h

@@ -0,0 +1,255 @@
+
+#ifndef BB_TYPEINFO_H
+#define BB_TYPEINFO_H
+
+#include "bbassert.h"
+#include "bbobject.h"
+#include "bbarray.h"
+#include "bbfunction.h"
+
+struct bbClassTypeInfo;
+
+struct bbTypeInfo{
+
+	bbString name;
+	bbString kind;
+	
+	bbString getName(){
+		return name;
+	}
+	
+	bbString getKind(){
+		return kind;
+	}
+	
+	virtual bbString toString();
+
+	virtual bbTypeInfo *pointeeType();
+	
+	virtual bbTypeInfo *elementType();
+	
+	virtual int arrayRank();
+	
+	virtual bbTypeInfo *returnType();
+	
+	virtual bbArray<bbTypeInfo*> paramTypes();
+	
+	virtual bbTypeInfo *superType();
+	
+	virtual bbBool extendsType( bbTypeInfo *type );
+	
+	virtual bbArray<bbDeclInfo*> getDecls();
+	
+	bbDeclInfo *getDecl( bbString name );
+	
+	bbDeclInfo *getDecl( bbString name,bbTypeInfo *type );
+	
+	bbArray<bbDeclInfo*> getDecls( bbString name );
+	
+	static bbTypeInfo *getType( bbString cname );
+	
+	static bbArray<bbTypeInfo*> getTypes();
+};
+
+template<class T> bbTypeInfo *bbGetType();
+
+struct bbUnknownTypeInfo : public bbTypeInfo{
+
+	bbUnknownTypeInfo();
+};
+
+struct bbVoidTypeInfo : public bbTypeInfo{
+
+	static bbVoidTypeInfo instance;
+
+	bbVoidTypeInfo();
+};
+
+struct bbObjectTypeInfo : public bbTypeInfo{
+
+	static bbObjectTypeInfo instance;
+
+	bbObjectTypeInfo();
+	
+	bbTypeInfo *superType();
+	
+	bbBool extendsType( bbTypeInfo *type );
+	
+	bbArray<bbDeclInfo*> getDecls();
+};
+
+struct bbPrimTypeInfo : public bbTypeInfo{
+
+	bbPrimTypeInfo( bbString name );
+};
+
+template<class T> struct bbPointerTypeInfo : public bbTypeInfo{
+
+	bbPointerTypeInfo(){
+		this->name=bbGetType<T>()->name+" Ptr";
+		this->kind="Pointer";
+	}
+	
+	bbTypeInfo *pointeeType(){
+		return bbGetType<T>();
+	}
+};
+
+template<class T,int D> struct bbArrayTypeInfo : public bbTypeInfo{
+
+	bbArrayTypeInfo(){
+		this->name=bbGetType<T>()->name+"["+BB_T(",").dup(D-1)+"]";
+		this->kind="Array";
+	}
+	
+	bbTypeInfo *elementType(){
+		return bbGetType<T>();
+	}
+	
+	int arrayRank(){
+		return D;
+	}
+};
+
+template<class R,class...A> struct bbFunctionTypeInfo : public bbTypeInfo{
+
+	bbFunctionTypeInfo(){
+		this->name=bbGetType<R>()->name+"("+BB_T(",").join( bbArray<bbString>( { bbGetType<A>()->name... },int(sizeof...(A)) ) )+")";
+		this->kind="Function";
+	}
+	
+	bbTypeInfo *returnType(){
+		return bbGetType<R>();
+	}
+	
+	bbArray<bbTypeInfo*> paramTypes(){
+		return bbArray<bbTypeInfo*>( { bbGetType<A>()... },int(sizeof...(A)) );
+	}
+
+};
+
+template<class...A> struct bbFunctionTypeInfo<void,A...> : public bbTypeInfo{
+
+	bbFunctionTypeInfo(){
+		this->name=BB_T("Void(")+BB_T(",").join( bbArray<bbString>( { bbGetType<A>()->name... },int(sizeof...(A)) ) )+")";
+		this->kind="Function";
+	}
+	
+	bbTypeInfo *returnType(){
+		return &bbVoidTypeInfo::instance;
+	}
+	
+	bbArray<bbTypeInfo*> paramTypes(){
+		return bbArray<bbTypeInfo*>( { bbGetType<A>()... },int(sizeof...(A)) );
+	}
+
+};
+
+struct bbClassDecls{
+
+	bbClassDecls *_succ;
+	bbDeclInfo **_decls=0;
+	int _numDecls=0;
+
+	bbClassDecls( bbClassTypeInfo *classType );
+	
+	bbDeclInfo **decls();
+	
+	int numDecls();
+	
+	virtual bbDeclInfo **initDecls(){
+		return 0;
+	}
+};
+
+struct bbClassTypeInfo : public bbTypeInfo{
+
+	bbClassTypeInfo *_succ=0;
+	bbClassDecls *_decls=0;
+	
+	bbClassTypeInfo( bbString name,bbString kind );
+	
+	bbBool extendsType( bbTypeInfo *type );
+	
+	bbArray<bbDeclInfo*> getDecls();
+	
+	bbString toString(){
+		return kind+" "+name;
+	}
+	
+	static bbClassTypeInfo *getNamespace( bbString name );
+};
+
+#define BB_PRIM_TYPEINFO( TYPE,ID ) inline bbTypeInfo *bbGetType( TYPE const& ){ \
+	static bbPrimTypeInfo info( ID ); \
+	return &info; \
+}
+
+BB_PRIM_TYPEINFO( bbBool,"Bool" )
+BB_PRIM_TYPEINFO( bbByte,"Byte" )
+BB_PRIM_TYPEINFO( bbUByte,"UShort" )
+BB_PRIM_TYPEINFO( bbShort,"Short" )
+BB_PRIM_TYPEINFO( bbUShort,"UShort" )
+BB_PRIM_TYPEINFO( bbInt,"Int" )
+BB_PRIM_TYPEINFO( bbUInt,"UInt" )
+BB_PRIM_TYPEINFO( bbLong,"Long" )
+BB_PRIM_TYPEINFO( bbULong,"ULong" )
+BB_PRIM_TYPEINFO( bbFloat,"Float" )
+BB_PRIM_TYPEINFO( bbDouble,"Double" )
+BB_PRIM_TYPEINFO( bbString,"String" )
+BB_PRIM_TYPEINFO( bbCString,"CString" )
+BB_PRIM_TYPEINFO( bbVariant,"Variant" )
+
+inline bbTypeInfo *bbGetType( bbObject* const& ){
+
+	return &bbObjectTypeInfo::instance;
+}
+
+template<class T> bbTypeInfo *bbGetType( T const& ){
+	static bbUnknownTypeInfo info;
+	
+	return &info;
+}
+
+template<class T> bbTypeInfo *bbGetType( T* const& ){
+	static bbPointerTypeInfo<T> info;
+	
+	return &info;
+}
+
+template<class T,int D> bbTypeInfo *bbGetType( bbArray<T,D> const& ){
+	static bbArrayTypeInfo<T,D> info;
+	
+	return &info;
+}
+
+template<class R,class...A> bbTypeInfo *bbGetFuncType(){
+	static bbFunctionTypeInfo<R,A...> info;
+	
+	return &info;
+}
+
+template<class R,class...A> bbTypeInfo *bbGetType( R(*)(A...) ){
+	return bbGetFuncType<R,A...>();
+}
+
+template<class R,class...A> bbTypeInfo *bbGetType( bbFunction<R(A...)> const& ){
+	return bbGetFuncType<R,A...>();
+}
+
+template<class T> bbTypeInfo *bbGetType( bbGCVar<T> const& ){
+
+	return bbGetType<T*>();
+}
+
+template<> inline bbTypeInfo *bbGetType<void>(){
+
+	return &bbVoidTypeInfo::instance;
+}
+
+template<class T> bbTypeInfo *bbGetType(){
+
+	return bbGetType( *(T*)0 );
+}
+
+#endif

+ 24 - 0
modules/monkey/native/bbtypes.h

@@ -19,10 +19,34 @@ typedef double bbDouble;
 typedef unsigned short bbChar;
 
 class bbString;
+
 template<class T> class bbFunction;
+
 template<class T,int D=1> class bbArray;
+
 template<class T> struct bbGCVar;
 
+struct bbVariant;
+
+struct bbTypeInfo;
+
+struct bbDeclInfo;
+
+namespace detail{
+
+	template<int...I> struct seq { };
+	
+    template<int N, int...I> struct gen_seq : gen_seq<N-1,N-1,I...> { };
+	
+    template<int...I> struct gen_seq<0,I...> : seq<I...> { };
+    
+	template<typename T> struct remove_pointer { typedef T type; };
+
+	template<typename T> struct remove_pointer<T*> { typedef typename remove_pointer<T>::type type; };
+}
+
+template<class T> bbTypeInfo *bbGetType();
+
 bbString bbTypeName( const char *type );
 
 #endif

+ 4 - 0
modules/monkey/native/bbvariant.cpp

@@ -0,0 +1,4 @@
+
+#include "bbvariant.h"
+
+bbVariant::RepBase bbVariant::_null;

+ 153 - 12
modules/monkey/native/bbvariant.h

@@ -2,49 +2,190 @@
 #ifndef BB_VARIANT_H
 #define BB_VARIANT_H
 
-class bbVariant{
+#include "bbtypeinfo.h"
 
+struct bbVariant{
+
+	template<class T> static bbObject *toObject( T *p,typename T::bb_object_type d=0 ){
+		return p;
+	}
+
+	template<class T> static bbObject *toObject( T const& ){
+		bbRuntimeError( "Variant cast failed" );
+		return 0;
+	}
+
+	template<class T,class C> static T castObject( bbObject *p,typename C::bb_object_type d=0 ){
+		return dynamic_cast<T>( p );
+	}
+
+	template<class T,class C> static T castObject(...){
+		bbRuntimeError( "Variant cast failed" );
+		return {};
+	}
+	
 	struct RepBase{
+	
+		int _refs=1;
+	
 		virtual ~RepBase(){
 		}
+		
+		virtual void gcMark(){
+		}
+		
+		virtual bbTypeInfo *getType(){
+			return &bbVoidTypeInfo::instance;
+		}
+		
+		virtual bbObject *getObject(){
+			return 0;
+		}
+		
+		virtual bbVariant invoke( bbArray<bbVariant> params ){
+			bbRuntimeError( "Variant is not invokable" );
+			return {};
+		}
 	};
 	
 	template<class T> struct Rep : public RepBase{
-		T t;
+	
+		T value;
+		
+		Rep( const T &value ):value( value ){
+		}
+		
+		virtual void gcMark(){
+			bbGCMark( value );
+		}
+		
+		virtual bbTypeInfo *getType(){
+			return bbGetType<T>();
+		}
+		
+		virtual bbObject *getObject(){
+			return toObject( value );
+		}
 	};
 	
+	template<class R,class...A> struct FuncRep : public Rep<bbFunction<R(A...)>>{
+
+		FuncRep( bbFunction<R(A...)> func ):Rep<bbFunction<R(A...)>>( func ){
+		}
+		
+		template<int...I> R invoke( bbArray<bbVariant> params,detail::seq<I...> ){
+
+			return this->value( params[I].get<A>()... );
+		}
+	
+		virtual bbVariant invoke( bbArray<bbVariant> params ){
+		
+			return bbVariant{ invoke( params,detail::gen_seq<sizeof...(A)>{} ) };
+		}
+	};
+	
+	template<class...A> struct FuncRep<void,A...> : public Rep<bbFunction<void(A...)>>{
+
+		FuncRep( bbFunction<void(A...)> func ):Rep<bbFunction<void(A...)>>( func ){
+		}
+		
+		template<int...I> void invoke( bbArray<bbVariant> params,detail::seq<I...> ){
+
+			this->value( params[I].get<A>()... );
+		}
+	
+		virtual bbVariant invoke( bbArray<bbVariant> params ){
+		
+			invoke( params,detail::gen_seq<sizeof...(A)>{} );
+			
+			return {};
+		}
+	};
+	
+	static RepBase _null;
+	
 	RepBase *_rep;
 	
 	void retain()const{
-		++_rep->refs;
+		++_rep->_refs;
 	}
 	
 	void release(){
-		if( !--_rep->refs ) {}//delete rep;
+		if( !--_rep->_refs && _rep!=&_null ) delete _rep;
 	}
 	
-	public:
+	// ***** public *****
 	
-	template<class T> bbVariant( const T &t ):_rep( new Rep<T>( t ) ){
-		retain();
+	bbVariant():_rep( &_null ){
 	}
 	
-	bbVariant( const bbVariant &t ):_rep( t._rep ){
+	bbVariant( const bbVariant &v ):_rep( v._rep ){
 		retain();
 	}
 	
-	bbVariant &operator=( const bbVariant &t ){
-		t.retain();
+	template<class T> explicit bbVariant( const T &t ):_rep( new Rep<T>( t ) ){
+	}
+	
+	template<class T> explicit bbVariant( const bbGCVar<T> &t ):_rep( new Rep<T*>( t.get() ) ){
+	}
+	
+	template<class R,class...A> explicit bbVariant( bbFunction<R(A...)> func ) : _rep( new FuncRep<R,A...>( func ) ){
+	}
+	
+	template<class R,class...A> explicit bbVariant( R(*func)(A...) ):_rep( new FuncRep<R,A...>( bbMakefunc( func ) ) ){
+	}
+	
+	~bbVariant(){
+		release();
+	}
+	
+	bbVariant &operator=( const bbVariant &v ){
+		v.retain();
 		release();
-		_rep=t._rep;
+		_rep=v._rep;
 		return *this;
 	}
 	
+	bbTypeInfo *getType()const{
+		return _rep->getType();
+	}
+	
 	template<class T> T get()const{
+	
 		Rep<T> *p=dynamic_cast<Rep<T>*>( _rep );
-		return p->t;
+		
+		if( p ) return p->value;
+		
+//		bbTypeInfo *type=bbGetType<T>();
+		
+//		if( type->kind=="Class" ){
+		
+			bbObject *obj=_rep->getObject();
+			
+			typedef typename detail::remove_pointer<T>::type C;
+			
+			return castObject<T,C>( obj );
+//		}
+		
+		bbRuntimeError( "Variant cast failed" );
+		
+		return T{};
+	}
+	
+	bbVariant invoke( bbArray<bbVariant> params ){
+	
+		return _rep->invoke( params );
+	}
+	
+	operator bool()const{
+	
+		return _rep!=&_null;
 	}
 };
 
+inline void bbGCMark( const bbVariant &v ){
+
+	v._rep->gcMark();
+}
 
 #endif

+ 202 - 20
modules/monkey/types.monkey2

@@ -383,6 +383,204 @@ Struct @String ="bbString"
 	
 End
 
+#rem monkeydoc String wrapper type for native 'char *' strings.
+
+This type should only be used when declaring parameters for extern functions.
+
+#end
+Struct @CString="bbCString"
+End
+
+#rem monkeydoc Variant type.
+
+The 'Variant' type is a primitive type that can be used to 'box' values of any type.
+
+An uninitialized variant will contain a 'null' value (of type Void) until you assign something to it.
+
+A variant is 'true' if it contains any value with a non-void type (including a bool false value!) and 'false' if it is uninitialized and has no (void) type.
+
+Any type of value can be implicitly converted to a variant.
+
+To retrieve the value contained in a variant, you must explicitly cast the variant to the desired type. Note that the cast must specify the exact type of the value already contained in the variant, or a runtime error will occur.
+
+The one exception to this is if the variant contains a class object, in which case you can cast the variant to any valid base class of the object.
+
+#end
+Struct @Variant="bbVariant"
+
+	#rem monkeydoc Type of the variant value.
+	#end
+	Property Type:TypeInfo()="getType"
+	
+End
+
+#rem monkeydoc Runtime type information.
+#End
+Class @TypeInfo Extends Void="bbTypeInfo"
+
+	#rem monkeydoc Type name.
+	#end
+	Property Name:String()="getName"
+	
+	#rem monkeydoc Type kind.
+	
+	Will be one of: Unknown, Primitve, Pointer, Array, Function, Class, Namespace.
+	
+	#end
+	Property Kind:String()="getKind"
+	
+	#rem monkeydoc Pointer pointee type.
+	
+	If the type is a pointer type, returns the type of what it's pointing at.
+	
+	If the type is not a pointer type a runtime exception occurs.
+	
+	#end
+	Property PointeeType:TypeInfo()="pointeeType"
+
+	#rem monkeydoc Array element type.
+	
+	If the type is an array type, returns the array element type.
+	
+	If the type is not an array type a runtime exception occurs.
+	
+	#end
+	Property ElementType:TypeInfo()="elementType"
+	
+	#rem monkeydoc Array rank.
+	
+	If the type is an array type, returns rank of the array.
+	
+	If the type is not an array type a runtime exception occurs.
+	
+	#end
+	Property ArrayRank:Int()="arrayRank"
+	
+	#rem monkeydoc Function return type.
+	
+	If the type is a function type, returns the return type of the functions.
+	
+	If the type is not a function type a runtime exception occurs.
+	
+	#end
+	Property ReturnType:TypeInfo()="returnType"
+	
+	#rem monkeydoc Function parameter types.
+	
+	If the type is a function type, returns the types of the function parameters.
+	
+	If the type is not a function type a runtime exception occurs.
+	
+	#end
+	Property ParamTypes:TypeInfo[]()="paramTypes"
+	
+	#rem monkeydoc class super type.
+	
+	If the type is a class type, returns the type of the super class.
+	
+	If the type is not a class type a runtime exception occurs.
+	
+	#end
+	Property SuperType:TypeInfo()="superType"
+	
+	#rem monkeydoc Gets string representation of type.
+	#end
+	Method To:String()="toString"
+	
+	#rem monkeydoc class or namespace member decls.
+	
+	If the type is a class or namespace type, returns the members of the type.
+	
+	If the type is not a class or namespace type a runtime exception occurs.
+	
+	#end
+	Method GetDecls:DeclInfo[]()="getDecls"
+	
+	#rem monkeydoc Gets the unique member decl with the given name.
+	
+	If there are multiple members with the same name, null is returned.
+	
+	#end
+	Method GetDecl:DeclInfo( name:String )="getDecl"
+	
+	#rem monkeydoc Gets the member decl with the given name and type.
+	#end
+	Method GetDecl:DeclInfo( name:String,type:TypeInfo )="getDecl"
+	
+	#rem monkeydoc Gets the member decls with the given name.
+	#end
+	Method GetDecls:DeclInfo[]( name:String )="getDecls"
+	
+	#rem monkeydoc Checks whether a class extends a class.
+	#end
+	Method ExtendsType:Bool( type:TypeInfo )="extendsType"
+
+	#rem monkeydoc Gets a user defined type by name.
+	
+	Only user defined types are returned by this function.
+	
+	#end
+	Function GetType:TypeInfo( name:String )="bbTypeInfo::getType"
+	
+	#rem monkeydoc Gets all user defined types.
+	
+	Only user defined types are returned by this function.
+	
+	#end
+	Function GetTypes:TypeInfo[]()="bbTypeInfo::getTypes"
+End
+
+#rem monkeydoc Runtime declaration information.
+#end
+Class DeclInfo Extends Void="bbDeclInfo"
+
+	#rem monkeydoc Declaration name.
+	#end
+	Property Name:String()="getName"
+	
+	#rem monkeydoc Declaration kind.
+	
+	This will be one of: Field, Global, Method, Function.
+	
+	#end
+	Property Kind:String()="getKind"
+	
+	#rem monkeydoc Declaration type.
+	#end
+	Property Type:TypeInfo()="getType"
+	
+	#rem monkeydoc Gets string representation of decl.
+	#end
+	Method To:String()="toString"
+	
+	#rem monkeydoc Sets field or global value.
+
+	If the declaration kind is 'Global', the `instance` parameter is ignored.
+	
+	A runtime error will occur if the declaration kind is not 'Field' or 'Global'.
+	
+	#end
+	Method Set( instance:Variant,value:Variant )="set"
+	
+	#rem monkeydoc Gets field or global value.
+	
+	If the declaration kind is 'Global', the `instance` parameter is ignored.
+	
+	A runtime error will occur if the declaration kind is not 'Field' or 'Global'.
+
+	#end
+	Method Get:Variant( instance:Variant )="get"
+	
+	#rem monkeydoc Invokes method or function.
+
+	If the declaration kind is 'Function', the `instance` parameter is ignored.
+
+	A runtime error will occur if the declaration kind is not 'Method' or 'Function'.
+	
+	#end
+	Method Invoke:Variant( instance:Variant,params:Variant[] )="invoke"
+End
+
 #rem monkeydoc Primtive array type.
 
 This is a 'pseduo type' extended by all array types.
@@ -465,6 +663,10 @@ End
 #end
 Class @Object="bbObject"
 
+	#rem monkeydoc The runtime typ eof the object
+	#end
+	Property InstanceType:TypeInfo()="typeof"
+	
 	#rem monkeydoc @hidden
 	#end
 	Method typeName:Void Ptr()="typeName"
@@ -477,23 +679,3 @@ End
 Class @Throwable="bbThrowable"
 
 End
-
-#rem monkeydoc @hidden
-#end
-Function TypeName:String( type:CString )="bbTypeName"
-
-#rem monkeydoc String wrapper type for native 'char *' strings.
-
-This type should only be used when declaring parameters for extern functions.
-
-#end
-Struct CString="bbCString"
-End
-
-#rem monkeydoc String wrapper type for native 'wchar_t *' strings.
-
-This type should only be used when declaring parameters for extern functions.
-
-#end
-Struct WString="bbWString"
-End

+ 17 - 12
src/mx2cc/builder.monkey2

@@ -31,6 +31,8 @@ Class BuildOpts
 	
 	Field geninfo:Bool
 	
+	Field wholeArchive:Bool
+	
 End
 
 Class BuilderInstance
@@ -77,6 +79,8 @@ Class BuilderInstance
 		
 		Builder=self
 
+		If Int( GetEnv( "MX2_WHOLE_ARCHIVE" ) ) opts.wholeArchive=True
+		
 		If opts.target="desktop"
 		
 			opts.target=HostOS
@@ -246,7 +250,7 @@ Class BuilderInstance
 		
 			Local module:=modules[modules.Length-i-1]
 
-			If module<>mainModule product.LD_LIBS.Push( module.outputDir+module.name+".a" )
+			If module<>mainModule product.MOD_LIBS.Push( module.outputDir+module.name+".a" )
 			
 		Next
 		
@@ -489,6 +493,7 @@ Class BuilderInstance
 		Type.FloatType=Null
 		Type.DoubleType=Null
 		Type.StringType=Null
+		Type.VariantType=Null
 		Type.ArrayClass=Null
 		Type.ObjectClass=Null
 		Type.ThrowableClass=Null
@@ -518,16 +523,14 @@ Class BuilderInstance
 		Type.FloatType=New PrimType( TCast<ClassType>( types.nodes["@float"] ) )
 		Type.DoubleType=New PrimType( TCast<ClassType>( types.nodes["@double"] ) )
 		Type.StringType=New PrimType( TCast<ClassType>( types.nodes["@string"] ) )
+		Type.VariantType=New PrimType( TCast<ClassType>( types.nodes["@variant"] ) )
 		
 		Type.ArrayClass=TCast<ClassType>( types.nodes["@Array"] )
 		Type.ObjectClass=TCast<ClassType>( types.nodes["@object"] )
 		Type.ThrowableClass=TCast<ClassType>( types.nodes["@throwable"] )
-		
-		Type.CStringClass=TCast<ClassType>( types.nodes["CString"] )
-		Type.WStringClass=TCast<ClassType>( types.nodes["WString"] )
-		Type.Utf8StringClass=TCast<ClassType>( types.nodes["Utf8String"] )
 
-		Type.ExceptionClass=TCast<ClassType>( types.nodes["@Exception"] )
+		Type.CStringClass=TCast<ClassType>( types.nodes["@cstring"] )
+		Type.TypeInfoClass=TCast<ClassType>( types.nodes["@typeinfo"] )
 
 		rootNamespace.Insert( "void",Type.VoidType )
 		rootNamespace.Insert( "bool",Type.BoolType )
@@ -542,14 +545,13 @@ Class BuilderInstance
 		rootNamespace.Insert( "float",Type.FloatType )
 		rootNamespace.Insert( "double",Type.DoubleType )
 		rootNamespace.Insert( "string",Type.StringType )
+		rootNamespace.Insert( "variant",Type.VariantType )
+		
 		rootNamespace.Insert( "object",Type.ObjectClass )
 		rootNamespace.Insert( "throwable",Type.ThrowableClass )
-		
-		rootNamespace.Insert( "CString",Type.CStringClass )
-		rootNamespace.Insert( "WString",Type.WStringClass )
-		rootNamespace.Insert( "Utf8String",Type.Utf8StringClass )
-		
-		rootNamespace.Insert( "Exception",Type.ExceptionClass )
+
+		rootNamespace.Insert( "cstring",Type.CStringClass )
+		rootNamespace.Insert( "typeinfo",Type.TypeInfoClass )
 		
 		Type.BoolType.Semant()
 		Type.ByteType.Semant()
@@ -563,9 +565,12 @@ Class BuilderInstance
 		Type.FloatType.Semant()
 		Type.DoubleType.Semant()
 		Type.StringType.Semant()
+		Type.VariantType.Semant()
 		Type.ArrayClass.Semant()
 		Type.ObjectClass.Semant()
 		Type.ThrowableClass.Semant()
+		Type.CStringClass.Semant()
+		Type.TypeInfoClass.Semant()
 	End
 	
 	Method ImportFile:Void( path:String )

+ 28 - 4
src/mx2cc/buildproduct.monkey2

@@ -14,7 +14,7 @@ Class BuildProduct
 
 	Field SRC_FILES:=New StringStack
 	Field OBJ_FILES:=New StringStack
-	Field LD_LIBS:=New StringStack
+	Field MOD_LIBS:=New StringStack
 	Field LD_SYSLIBS:=New StringStack
 	Field ASSET_FILES:=New StringStack
 	Field DLL_FILES:=New StringStack
@@ -292,6 +292,9 @@ Class GccBuildProduct Extends BuildProduct
 		Case ".asm",".s"
 			
 			cmd=AS_CMD
+			Local opts:=GetEnv( "MX2_AS_OPTS" )
+			If opts cmd+=" "+opts
+			
 			isasm=True
 		End
 			
@@ -488,13 +491,30 @@ Class GccBuildProduct Extends BuildProduct
 			lnkFiles+=" ~q"+obj+"~q"
 		Next
 		
-		For Local lib:=Eachin LD_LIBS
+		If opts.wholeArchive 
+#If __TARGET__="macos"
+			lnkFiles+=" -Wl,-all_load"
+#Else
+			lnkFiles+=" -Wl,--whole-archive"
+#Endif
+		Endif
+		
+		For Local lib:=Eachin MOD_LIBS
 			lnkFiles+=" ~q"+lib+"~q"
 		Next
-	
+
+		If opts.wholeArchive 
+#If __TARGET__="macos"
+'			lnkFiles+=" -Wl,-all_load"
+#Else
+			lnkFiles+=" -Wl,--no-whole-archive"
+#Endif
+		Endif
+		
 		lnkFiles+=" "+LD_SYSLIBS.Join( " " )
 		
 		If opts.target="windows"
+			lnkFiles=lnkFiles.Replace( " -Wl,"," " )
 			Local tmp:=AllocTmpFile( "lnkFiles" )
 			SaveString( lnkFiles,tmp )
 			cmd+=" -Wl,@"+tmp
@@ -680,9 +700,13 @@ Class IosBuildProduct Extends GccBuildProduct
 		
 		Local cmd:="libtool -static -o ~q"+outputFile+"~q ~q"+arc+"~q"
 		
-		For Local lib:=Eachin LD_LIBS
+		If opts.wholeArchive cmd+=" -Wl,--whole-archive"
+		
+		For Local lib:=Eachin MOD_LIBS
 			cmd+=" ~q"+lib+"~q"
 		Next
+
+		If opts.wholeArchive cmd+=" -Wl,--no-whole-archive"
 		
 		For Local lib:=Eachin LD_SYSLIBS
 			If lib.ToLower().EndsWith( ".a~q" ) cmd+=" "+lib

+ 19 - 7
src/mx2cc/class.monkey2

@@ -485,17 +485,16 @@ Class ClassType Extends Type
 	Method DistanceToType:Int( type:Type ) Override
 	
 		If type=Self Return 0
+		
+		'no struct->bool as yet.
+		If type=BoolType Return (IsClass Or IsInterface) ? MAX_DISTANCE Else -1
+		
+		If type=VariantType Return MAX_DISTANCE
 
 		'Cast to super class
 		Local dist:=DistanceToBase( type )
 		If dist>=0 Return dist
 		
-		'Cast to bool
-		If type=BoolType
-			If IsClass Or IsInterface Return MAX_DISTANCE
-			Return -1
-		Endif
-
 		'Operator To:
 		Local func:=FindToFunc( type )
 		If func Return MAX_DISTANCE
@@ -514,11 +513,16 @@ Class ClassType Extends Type
 	
 	Method UpCast:Value( rvalue:Value,type:Type ) Override
 	
+		If type.Equals( rvalue.type ) Return rvalue
+
 		'Cast to superclass
 		Local dist:=DistanceToBase( type )
 		If dist>=0 Return New UpCastValue( type,rvalue )
 		
-		'Cast to bool
+		'instance->variant
+		If type=VariantType Return New UpCastValue( type,rvalue )
+	
+		'instance->bool
 		If type=BoolType
 			If IsClass Or IsInterface Return New UpCastValue( type,rvalue )
 		Else
@@ -528,6 +532,7 @@ Class ClassType Extends Type
 		Endif
 
 		Throw New SemantEx( "Unable to convert value from type '"+rvalue.type.ToString()+"' to type '"+type.ToString()+"'" )
+		
 		Return Null
 	End
 
@@ -710,6 +715,13 @@ Class ClassScope Extends Scope
 		Return "T"+outer.TypeId+"_"+ctype.cdecl.ident.Replace( "_","_0" )+args+"_2"
 	End
 	
+	Property IsInstanceOf:Bool() Override
+	
+		If ctype.instanceOf Return True
+		
+		Return Super.IsInstanceOf
+	End
+	
 	Property IsGeneric:Bool() Override
 
 		If ctype.IsGeneric Return True

+ 4 - 5
src/mx2cc/enum.monkey2

@@ -94,12 +94,11 @@ Class EnumType Extends Type
 	
 		If type=Self Return 0
 		
+		If type=Type.VariantType Return MAX_DISTANCE
+
+		'enum->integral/bool.		
 		Local ptype:=TCast<PrimType>( type )
-		If ptype
-			If ptype=Type.BoolType Return MAX_DISTANCE
-			If ptype.IsIntegral Return MAX_DISTANCE
-			Return -1
-		Endif
+		If ptype And (ptype=Type.BoolType Or ptype.IsIntegral) Return MAX_DISTANCE
 		
 		Return -1
 	End

+ 24 - 0
src/mx2cc/expr.monkey2

@@ -979,3 +979,27 @@ Class PointerTypeExpr Extends Expr
 		Return type.ToString()+" Ptr"
 	End
 End
+
+Class TypeofExpr Extends Expr
+
+	Field expr:Expr
+	Field istype:Bool
+	
+	Method New( expr:Expr,istype:Bool,srcpos:Int,endpos:Int )
+		Super.New( srcpos,endpos )
+		
+		Self.expr=expr
+		Self.istype=istype
+	End
+	
+	Method OnSemant:Value( scope:Scope ) Override
+	
+		If istype Return New TypeofTypeValue( expr.SemantType( scope ) )
+		
+		Local rvalue:=expr.SemantRValue( scope )
+		If rvalue.type=Type.VoidType Throw New SemantEx( "Invalid Typeof expression" )
+		
+		Return New TypeofValue( rvalue )
+	End
+	
+End

+ 4 - 0
src/mx2cc/func.monkey2

@@ -570,6 +570,8 @@ Class FuncListValue Extends Value
 	
 	Method UpCast:Value( type:Type ) Override
 	
+		If type.Equals( Type.VariantType ) Return New UpCastValue( Type.VariantType,ToRValue() )
+	
 		Local ftype:=TCast<FuncType>( type )
 		If Not ftype Throw New UpCastEx( Self,type )
 		
@@ -630,6 +632,8 @@ Class FuncListType Extends Type
 	End
 	
 	Method DistanceToType:Int( type:Type ) Override
+	
+		If type.Equals( Type.VariantType ) Return funcs.Length=1 ? MAX_DISTANCE Else -1
 
 		Local ftype:=TCast<FuncType>( type )
 		If Not ftype Return -1

+ 1 - 1
src/mx2cc/mx2.monkey2

@@ -50,4 +50,4 @@ Using libc
 ' 3) edit .sh and .bat files to use new version (common.sh, common.bat)
 ' 4) ./rebuildall
 '
-Const MX2CC_VERSION:="1.0.8"
+Const MX2CC_VERSION:="1.0.9"

+ 6 - 18
src/mx2cc/mx2cc.monkey2

@@ -21,26 +21,14 @@ Using mx2..
 
 Global StartDir:String
 
-'Const TestArgs:="mcx2cc makedocs"
+Const TestArgs:="mx2cc makeapp -apptype=console -clean -verbose=3 src/mx2cc/test.monkey2"
 
-'Const TestArgs:="mx2cc makemods -clean -config=release monkey libc miniz stb-image stb-image-write stb-vorbis std"
-
-'Const TestArgs:="mx2cc makeapp -clean -config=release src/ted2/ted2.monkey2"
-
-'Const TestArgs:="mx2cc makeapp -apptype=console -clean -config=debug -target=desktop -semant -geninfo src/mx2cc/test.monkey2"
-Const TestArgs:="mx2cc makeapp -apptype=console -clean -config=debug -target=desktop -parse -geninfo src/mx2cc/translator_cpp.monkey2"
-
-'Const TestArgs:="mx2cc makeapp -clean -config=debug -target=desktop -product=D:/test_app/test.exe -assets=D:/test_app/assets -dlls=D:/test_app/ src/mx2cc/test.monkey2"
-
-'Const TestArgs:="mx2cc makeapp -clean src/ted2/ted2"
-
-'Const TestArgs:="mx2cc makemods -clean -config=release monkey libc miniz stb-image hoedown std"
-
-'Const TestArgs:="mx2cc makeapp -verbose -target=desktop -config=release src/mx2cc/mx2cc"
-
-'To build mx2cc...
+'To build with old mx2cc...
 '
-'Const TestArgs:="mx2cc makeapp -build -clean -apptype=console -config=release src/mx2cc/mx2cc.monkey2"
+'Creates: src/mx2cc/mx2cc.buildv.VERSION/windows_release/mx2cc.exe
+'
+'Const TestArgs:="mx2cc makemods -clean -config=release monkey libc miniz stb-image stb-image-write stb-vorbis std"
+'Const TestArgs:="mx2cc makeapp -build -apptype=console -clean -config=release src/mx2cc/mx2cc.monkey2"
 
 'To build rasbian mx2cc...
 '

+ 25 - 4
src/mx2cc/parser.monkey2

@@ -430,6 +430,7 @@ Class Parser
 			Default
 			
 				ident=ParseIdent()
+				If ident="@typeof" ident="Typeof"
 			End
 	
 			genArgs=ParseGenArgs()
@@ -1138,7 +1139,7 @@ Class Parser
 	
 	Method IsTypeIdent:Bool( ident:String )
 		Select ident
-		Case "void","bool","byte","ubyte","short","ushort","int","uint","long","ulong","float","double","string","object","throwable"
+		Case "void","bool","byte","ubyte","short","ushort","int","uint","long","ulong","float","double","string","object","throwable","variant","cstring","typeinfo"
 			Return True
 		End
 		Return False
@@ -1434,6 +1435,21 @@ Class Parser
 			Parse( ")" )
 			Return New CastExpr( type,expr,srcpos,EndPos )
 			
+		Case "typeof"
+		
+			Bump()
+			If CParse( "<" )
+				Local expr:=ParseType()
+				Parse( ">" )
+				Return New TypeofExpr( expr,True,srcpos,EndPos )
+			Else If CParse( "(" )
+				Local expr:=ParseExpr()
+				Parse( ")" )
+				Return New TypeofExpr( expr,False,srcpos,EndPos )
+			Endif
+			
+			Error( "Expecting 'Typeof' argument" )
+			
 		Case "true","false"
 		
 			Local value:=Parse()
@@ -1503,9 +1519,14 @@ Class Parser
 			Select Toke
 			Case "."
 				Bump()
-				Local ident:=CParseIdent()
-				If Not ident And Toke="new" ident=Parse()
-				If Not ident Error( "Expecting member identifier" )
+				Local ident:String
+				If CParse( "new" )
+					ident="new"
+				Else If CParse( "typeof" )
+					ident="Typeof"
+				Else
+					ident=ParseIdent()
+				Endif
 				expr=New MemberExpr( expr,ident,srcpos,EndPos )
 			Case "->"
 				Bump()

+ 7 - 0
src/mx2cc/scope.monkey2

@@ -36,6 +36,13 @@ Class Scope
 		Return ""
 	End
 	
+	Property IsInstanceOf:Bool() Virtual
+	
+		If outer Return outer.IsInstanceOf
+		
+		Return False
+	End
+	
 	'Is generic scope? ie: does scope have access to any generic types?
 	'
 	Property IsGeneric:Bool() Virtual

+ 17 - 89
src/mx2cc/test.monkey2

@@ -1,101 +1,29 @@
 
-#import "<std>"
+Namespace test
 
-Using std..
-
-Class UniformBuffer
-
-	Method Id<T>( name:String )
-	
-		Return Values<T>.Get( Self ).Id( name )
-	End
-
-	Method Set<T>( name:String,value:T )
-	
-		Values<T>.Get( Self ).Set( name,value )
-	End
-	
-	Method Clear<T>( name:String )
-	
-		Values<T>.Get( Self ).Clear( name )
-	End
-	
-	Method Exists<T>:Bool( name:String )
-	
-		Return Values<T>.Get( Self ).Exists( name )
-	End
-	
-	Method Get<T>:T( name:String )
-	
-		Return Values<T>.Get( Self ).Get( name )
-	End
-	
-	Private
-	
-	Struct Values<T>
-	
-		Global _valuesMap:=New Map<UniformBuffer,Values>
-
-		Function Get:Values( ubuffer:UniformBuffer )
-
-			Local values:=_valuesMap[ubuffer]
-			If values Return values
-
-			values=New Values
-			_valuesMap[ubuffer]=values
-			Return values
-		End
-	
-		Method Id:Int( name:String )
-		
-			Local id:=_ids[name]
-			If id Return id-1
-			
-			_values.Push( Null )
-			_exists.Push( False )
-			
-			_ids[name]=_values.Length
-			Return _values.Length-1
+#Import "<std>"
+#Import "<mojo>"
 
-		End
-		
-		Method Set( name:String,value:T )
-			Local id:=Id( name )
-			_values[id]=value
-			_exists[id]=True
-		End
-		
-		Method Clear( name:String )
-			Local id:=Id( name )
-			_exists[ id ]=False
-		End
-		
-		Method Get:T( name:String )
-			Local id:=Id( name )
-			Return _values[id]
-		End
-		
-		Method Exists:Bool( name:String )
-			Local id:=Id( name )
-			Return _exists[id]
-		End
-		
-		Private
-		
-		Field _ids:=New StringMap<Int>
-		
-		Field _values:=New Stack<T>
-		Field _exists:=New Stack<Bool>
+Using std..
+Using mojo..
 
-	End
+Function Test( v:Vec2f )
+End
 
+Enum E
+	X,Y,Z
 End
 
 Function Main()
 
-	Local ubuffer:=New UniformBuffer
+	Local e:=E.Z
+	
+'	Local v:=Variant( e )
+	
+'	Print v.Type
+	
+'	Print Int( Cast<E>( v ) )
 	
-	ubuffer.Set( "TestInt",1 )
-	Print ubuffer.Get<Int>( "TestInt" )
+	Local v2:=Variant( New Vec2( 1,1 ) )
 
 End

+ 4 - 7
src/mx2cc/test2.monkey2

@@ -1,8 +1,5 @@
 
-Enum EntityState
-	ENTERING
-	UPDATING
-	EXPLODING
-	ENDING
-	DONE
-End Enum
+Namespace test
+
+Class Socket
+End

+ 2 - 2
src/mx2cc/toker.monkey2

@@ -22,7 +22,7 @@ Global tokerInited:Bool
 Function InitToker:Void()
 	If tokerInited Return
 	tokerInited=True
-
+	
 	Local keyWords:="Namespace;Using;Import;Extern;"
 	keyWords+="Public;Private;Protected;Internal;Friend;"
 	keyWords+="Void;Bool;Byte;UByte;Short;UShort;Int;UInt;Long;ULong;Float;Double;String;Object;Continue;Exit;"
@@ -36,7 +36,7 @@ Function InitToker:Void()
 	keyWords+="Repeat;Until;Forever;"
 	keyWords+="For;To;Step;Next;"
 	keyWords+="Select;Case;Default;"
-	keyWords+="Try;Catch;Throw;Throwable;"
+	keyWords+="Try;Catch;Throw;Throwable;Variant;CString;TypeInfo;Typeof;"
 	keyWords+="Return;Print;Static;Cast;"
 	keyWords+="Extension;Protocol;Delete"
 

+ 5 - 25
src/mx2cc/translator.monkey2

@@ -7,6 +7,8 @@ Namespace mx2
 '
 Function IsGCType:Bool( type:Type )
 
+	If type=Type.VariantType Return true
+	
 	If TCast<FuncType>( type ) Return True
 	
 	If TCast<ArrayType>( type ) Return True
@@ -203,7 +205,7 @@ Class Translator
 			For Local vvar:=Eachin _gcframe.vars.Values
 				Uses( vvar.type )
 				If IsGCPtrType( vvar.type )
-					Emit( "bbGCMarkPtr("+VarName( vvar )+");" )
+					Emit( "bbGCMark("+VarName( vvar )+");" )
 				Else
 					Emit( "bbGCMark("+VarName( vvar )+");" )
 				Endif
@@ -212,7 +214,7 @@ Class Translator
 			For Local tmp:=Eachin _gcframe.tmps
 				Uses( tmp.type )
 				If IsGCPtrType( tmp.type )
-					Emit( "bbGCMarkPtr("+tmp.ident+");" )
+					Emit( "bbGCMark("+tmp.ident+");" )
 				Else
 					Emit( "bbGCMark("+tmp.ident+");" )
 				Endif
@@ -316,6 +318,7 @@ Class Translator
 				
 				Local cname:=ClassName( ctype )
 				Emit( "struct "+ClassName( ctype )+";" )
+				If GenTypeInfo( ctype ) Emit( "bbTypeInfo *bbGetType( "+cname+"* const& );" )
 				
 				If debug And Not ctype.cdecl.IsExtern
 					Local tname:=cname
@@ -470,27 +473,4 @@ Class Translator
 		_usesFiles[ fdecl.ident ]=fdecl
 	End
 	
-	'***** MISC *****
-
-	Method IsCValueType:Bool( type:Type )
-	
-		Local ctype:=TCast<ClassType>( type )
-		If ctype And ctype.IsStruct Return True
-	
-		Return TCast<PrimType>( type ) Or TCast<FuncType>( type ) Or TCast<ArrayType>( type )
-	End
-	
-	Method CFuncType:String( type:FuncType )
-	
-		Local retType:=TransType( type.retType )
-		
-		Local argTypes:=""
-		For Local i:=0 Until type.argTypes.Length
-			If argTypes argTypes+=","
-			argTypes+=TransType( type.argTypes[i] )
-		Next
-		
-		Return retType+"("+argTypes+")"
-	End
-
 End

+ 280 - 26
src/mx2cc/translator_cpp.monkey2

@@ -77,6 +77,7 @@ Class Translator_CPP Extends Translator
 		EmitBr()
 		For Local ctype:=Eachin fdecl.classes
 			If emitted[ClassName( ctype )] Continue
+			
 			EmitClassProto( ctype,fdecl,emitted )
 		Next
 		
@@ -112,9 +113,14 @@ Class Translator_CPP Extends Translator
 		Next
 		
 		For Local ctype:=Eachin fdecl.classes
+		
 			EmitClassMembers( ctype )
+			
+			EmitTypeInfo( ctype )
 		Next
 		
+		EmitTypeInfo( fdecl )
+		
 		EmitGlobalInits( fdecl )
 
 		EndDeps( ExtractDir( fdecl.cfile ) )
@@ -249,6 +255,7 @@ Class Translator_CPP Extends Translator
 		Emit( "if(done) return;" )
 		Emit( "done=true;")
 		
+		'initalize globals
 		Local gc:=False
 		For Local vvar:=Eachin fdecl.globals
 			If vvar.init Emit( Trans( vvar )+"="+Trans( vvar.init )+";" )
@@ -348,6 +355,14 @@ Class Translator_CPP Extends Translator
 		EmitBr()
 		Emit( "struct "+cname+xtends+"{" )
 		
+		If ctype.IsClass
+			Emit( "typedef "+cname+" *bb_object_type;" )
+		Else If ctype.IsInterface
+			Emit( "typedef "+cname+" *bb_object_type;" )
+		Else If ctype.IsStruct
+			Emit( "typedef "+cname+" bb_struct_type;" )
+		Endif
+		
 		If ctype.superType
 		
 			Local done:=New StringMap<Bool>
@@ -368,6 +383,8 @@ Class Translator_CPP Extends Translator
 			Next
 		Endif
 		
+		If GenTypeInfo( ctype ) Emit( "bbTypeInfo *typeof()const;" )
+		
 		Emit( "const char *typeName()const{return ~q"+cname+"~q;}" )
 		
 		'Emit fields...
@@ -473,6 +490,8 @@ Class Translator_CPP Extends Translator
 
 		Emit( "};" )
 		
+		If GenTypeInfo( ctype ) Emit( "bbTypeInfo *bbGetType( "+cname+"* const& );" )
+		
 		If debug
 			Local tname:=cname
 			If Not ctype.IsStruct tname+="*"
@@ -684,6 +703,171 @@ Class Translator_CPP Extends Translator
 
 	End
 	
+	Method EmitTypeInfo( fdecl:FileDecl )
+	
+		Local decls:=New Stack<String>
+	
+		For Local vvar:=Eachin fdecl.globals
+			If Not GenTypeInfo( vvar ) continue
+			Local fscope:=vvar.scope.FindFile()
+			If fscope.fdecl<>fdecl Continue
+			If vvar.scope<>fscope Continue
+			
+			Local id:=vvar.vdecl.ident
+			Local vname:=VarName( vvar )
+			decls.Push( "bbGlobalDecl(~q"+id+"~q,&"+vname+")" )
+		Next
+		
+		For Local func:=Eachin fdecl.functions
+			If Not GenTypeInfo( func ) Continue
+			Local fscope:=func.scope.FindFile()
+			If fscope.fdecl<>fdecl Continue
+			If func.scope<>fscope Continue
+
+			Local id:=func.fdecl.ident
+			Local fname:=FuncName( func )
+			Local args:=TransType( func.ftype.retType )
+			For Local arg:=Eachin func.ftype.argTypes
+				args+=","+TransType( arg )
+			Next
+			decls.Push( "bbFunctionDecl<"+args+">(~q"+id+"~q,&"+fname+")" )
+		Next
+		
+		If decls.Empty Return
+
+		Local tname:="mx2_"+fdecl.ident+"_typeinfo"
+	
+		Emit( "static struct "+tname+" : public bbClassDecls{" )
+		
+		Emit( tname+"():bbClassDecls(bbClassTypeInfo::getNamespace(~q"+fdecl.nmspace+"~q)){" )
+		Emit( "}" )
+		
+		Emit( "bbDeclInfo **initDecls(){" )
+		Emit( "return bbMembers("+decls.Join( "," )+");" )
+		Emit( "}" )
+		
+		Emit( "}_"+tname+";" )
+	End
+
+	Method EmitTypeInfo( ctype:ClassType )
+	
+		If Not GenTypeInfo( ctype ) Return
+	
+		Local fdecl:=ctype.scope.FindFile().fdecl
+
+		Local cdecl:=ctype.cdecl
+		Local cname:=ClassName( ctype )
+		Local rcname:="r"+cname
+
+		EmitBr()
+		Emit( "struct "+rcname+" : public bbClassTypeInfo{" )
+		
+		Emit( "static "+rcname+" instance;" )
+		
+		'struct decls_t
+		Emit( "static struct decls_t : public bbClassDecls{" )
+		
+		Emit( "decls_t():bbClassDecls(&instance){}" )
+		
+		'initDecls()
+		Emit( "bbDeclInfo **initDecls(){" )
+		
+		Local decls:=New StringStack
+		
+		If Not ctype.IsAbstract
+			If ctype.ctors.Length
+				For Local ctor:=Eachin ctype.ctors
+					Local args:=cname
+					For Local arg:=Eachin ctor.ftype.argTypes
+						If args args+=","
+						args+=TransType( arg )
+					Next
+					decls.Push( "bbCtorDecl<"+args+">()" )
+				Next
+			Else
+				'default ctor!
+				decls.Push( "bbCtorDecl<"+cname+">()" )
+			Endif
+		Endif
+		
+		For Local vvar:=Eachin ctype.fields
+			If Not GenTypeInfo( vvar ) Continue
+			
+			Local id:=vvar.vdecl.ident
+			Local vname:=VarName( vvar )
+			decls.Push( "bbFieldDecl(~q"+id+"~q,&"+cname+"::"+vname+")" )
+		Next
+
+		For Local func:=Eachin ctype.methods
+			If Not GenTypeInfo( func ) Continue
+			
+			Local id:=func.fdecl.ident
+			Local fname:=FuncName( func )
+			Local args:=cname+","+TransType( func.ftype.retType )
+			For Local arg:=Eachin func.ftype.argTypes
+				args+=","+TransType( arg )
+			Next
+			decls.Push( "bbMethodDecl<"+args+">(~q"+id+"~q,&"+cname+"::"+fname+")" )
+		Next
+		
+		For Local vvar:=Eachin fdecl.globals
+			If Not GenTypeInfo( vvar ) Continue
+			If vvar.scope<>ctype.scope Continue
+			
+			Local id:=vvar.vdecl.ident
+			Local vname:=VarName( vvar )
+			decls.Push( "bbGlobalDecl(~q"+id+"~q,&"+vname+")" )
+		Next
+		
+		For Local func:=Eachin fdecl.functions
+			If Not GenTypeInfo( func ) Continue
+			If func.scope<>ctype.scope Continue
+			
+			Local id:=func.fdecl.ident
+			Local fname:=FuncName( func )
+			Local args:=TransType( func.ftype.retType )
+			For Local arg:=Eachin func.ftype.argTypes
+				args+=","+TransType( arg )
+			Next
+			decls.Push( "bbFunctionDecl<"+args+">(~q"+id+"~q,&"+fname+")" )
+		Next
+		
+		Emit( "return bbMembers("+decls.Join( "," )+");" )
+		
+		Emit( "}" )
+		
+		Emit( "}decls;" )
+
+		'Ctor		
+		Emit( rcname+"():bbClassTypeInfo(~q"+ctype.Name+"~q,~q"+cdecl.kind.Capitalize()+"~q){" )
+		Emit( "}" )
+
+		'superType		
+		Emit( "bbTypeInfo *superType(){" )
+		If ctype.superType
+			Emit( "return bbGetType<"+ClassName( ctype.superType )+"*>();" )
+		Else
+			Emit( "return 0;" )
+		Endif		
+		Emit( "}" )
+		
+		Emit( "};" )
+		
+		Emit( rcname+" "+rcname+"::instance;" )
+		
+		Emit( rcname+"::decls_t "+rcname+"::decls;" )
+		
+		EmitBr()
+		Emit( "bbTypeInfo *"+cname+"::typeof()const{" )
+		Emit( "return &"+rcname+"::instance;" )
+		Emit( "}" )
+		
+		EmitBr()
+		Emit( "bbTypeInfo *bbGetType( "+cname+"* const& ){" )
+		Emit( "return &"+rcname+"::instance;" )
+		Emit( "}" )
+	End
+
 	Method EmitFunc( func:FuncValue,init:Bool=False )
 	
 		If func.fdecl.IsAbstract Return
@@ -792,7 +976,7 @@ Class Translator_CPP Extends Translator
 			If Not IsGCType( vvar.type ) Continue
 			Uses( vvar.type )
 			If IsGCPtrType( vvar.type )
-				Emit( "bbGCMarkPtr("+VarName( vvar )+");" )
+				Emit( "bbGCMark("+VarName( vvar )+");" )
 			Else
 				Emit( "bbGCMark("+VarName( vvar )+");" )
 			Endif
@@ -1233,35 +1417,44 @@ Class Translator_CPP Extends Translator
 		Local varValue:=Cast<VarValue>( value )
 		If varValue Return Trans( varValue )
 		
+		Local typeofValue:=Cast<TypeofValue>( value )
+		If typeofValue Return Trans( typeofValue )
+
+		Local typeofTypeValue:=Cast<TypeofTypeValue>( value )
+		If typeofTypeValue Return Trans( typeofTypeValue )
+		
 		Return "{* "+value.ToString()+" "+String.FromCString( value.typeName() )+" *}"
 	End
 	
 	Method Trans:String( value:UpCastValue )
 	
-		Uses( value.type )
+		Local src:="("+Trans( value.value )+")"
 	
-		Local t:="("+Trans( value.value )+")"
+		If value.type.Equals( value.value.type ) Return src
+	
+		Uses( value.type )
 		
-		If IsCValueType( value.type ) Return TransType( value.type )+t
+		If IsCValueType( value.type ) Return TransType( value.type )+src
 
-		Return "(("+TransType( value.type )+")"+t+")"
+		Return "(("+TransType( value.type )+")"+src+")"
 	End
 	
 	Method Trans:String( value:ExplicitCastValue )
 	
-		Uses( value.type )
+		Local src:="("+Trans( value.value )+")"
+
+		If value.type.Equals( value.value.type ) Return src
 	
-		Local ctype:=TCast<ClassType>( value.type )
-		If ctype 
-'			Uses( ctype )
-			Return "bb_object_cast<"+ClassName( ctype )+"*>("+Trans( value.value )+")"
-		Endif
+		Uses( value.type )
 		
-		Local t:="("+Trans( value.value )+")"
+		If value.value.type=Type.VariantType Return src+".get<"+TransType( value.type )+">()"
 		
-		If IsCValueType( value.type ) Return TransType( value.type )+t
-
-		Return "(("+TransType( value.type )+")"+t+")"
+		If IsCValueType( value.type ) Return TransType( value.type )+src
+		
+		Local ctype:=TCast<ClassType>( value.type )
+		If ctype Return "bb_object_cast<"+ClassName( ctype )+"*>"+src
+		
+		Return "(("+TransType( value.type )+")"+src+")"
 	End
 	
 	Method TransNull:String( type:Type )
@@ -1402,6 +1595,17 @@ Class Translator_CPP Extends Translator
 		Return "bbMethod(("+cname+"*)("+Trans( value.instance )+"),&"+cname+"::"+Trans( value.member )+")"
 	End
 	
+	Method Trans:String( value:FuncValue )
+	
+		Refs( value )
+	
+		If value.fdecl.kind="lambda" 
+			Return EmitLambda( value )
+		Endif
+		
+		Return FuncName( value )
+	End
+	
 	Method Trans:String( value:NewObjectValue )
 	
 		Local ctype:=value.ctype
@@ -1521,17 +1725,6 @@ Class Translator_CPP Extends Translator
 		Return "&"+Trans( value.value )
 	End
 	
-	Method Trans:String( value:FuncValue )
-	
-		Refs( value )
-	
-		If value.fdecl.kind="lambda" 
-			Return EmitLambda( value )
-		Endif
-		
-		Return FuncName( value )
-	End
-	
 	Method Trans:String( value:VarValue )
 	
 		Refs( value )
@@ -1545,6 +1738,18 @@ Class Translator_CPP Extends Translator
 		Return VarName( value )
 	End
 	
+	Method Trans:String( value:TypeofValue )
+	
+		Return "bbGetType("+Trans( value.value )+")"
+	End
+	
+	Method Trans:String( value:TypeofTypeValue )
+	
+		Refs( value.ttype )
+	
+		Return "bbGetType<"+TransType( value.ttype )+">()"
+	End
+	
 	'***** Args *****
 	
 	Method IsVolatile:Bool( arg:Value )
@@ -1641,4 +1846,53 @@ Class Translator_CPP Extends Translator
 		Return "bbArray<"+HeapVarType( type.elemType )+","+type.rank+">"
 	End
 	
+	'***** MISC *****
+
+	Method IsCValueType:Bool( type:Type )
+	
+		Local ctype:=TCast<ClassType>( type )
+		If ctype And ctype.IsStruct Return True
+	
+		Return TCast<PrimType>( type ) Or TCast<FuncType>( type ) Or TCast<ArrayType>( type )
+	End
+	
+	Method CFuncType:String( type:FuncType )
+	
+		Local retType:=TransType( type.retType )
+		
+		Local argTypes:=""
+		For Local i:=0 Until type.argTypes.Length
+			If argTypes argTypes+=","
+			argTypes+=TransType( type.argTypes[i] )
+		Next
+		
+		Return retType+"("+argTypes+")"
+	End
+
+End
+
+Function GenTypeInfo:Bool( vvar:VarValue )
+
+	Return vvar.vdecl.kind="field" Or vvar.vdecl.kind="global"
+End
+
+Function GenTypeInfo:Bool( func:FuncValue )
+
+	If func.fdecl.kind<>"method" And func.fdecl.kind<>"function" Return False
+
+	If func.IsExtension Return Null
+	
+	Return True
+End
+
+Function GenTypeInfo:Bool( ctype:ClassType )
+
+	If Not ctype.IsClass Return False
+
+	'This 'sort of' works, but no generics just yet!
+	If ctype.types Or ctype.scope.IsInstanceOf Return False
+	
+	If ctype.cdecl.IsExtension Return False
+	
+	Return True
 End

+ 33 - 14
src/mx2cc/type.monkey2

@@ -22,16 +22,14 @@ Class Type Extends SNode
 	Global FloatType:PrimType
 	Global DoubleType:PrimType
 	Global StringType:PrimType
+	Global VariantType:PrimType
 	
 	Global ArrayClass:ClassType
 	Global ObjectClass:ClassType
 	Global ThrowableClass:ClassType
 	
 	Global CStringClass:ClassType
-	Global WStringClass:ClassType
-	Global Utf8StringClass:ClassType
-	
-	Global ExceptionClass:ClassType
+	Global TypeInfoClass:ClassType
 	
 	Field _alias:Type
 	
@@ -218,7 +216,7 @@ Class PrimType Extends Type
 	End
 	
 	Method ToString:String() Override
-		Return ctype.cdecl.ident.Slice( 1 )	'slice off '@' prefix
+		Return ctype.cdecl.ident'.Slice( 1 )	'slice off '@' prefix
 	End
 	
 	Property Name:String() Override
@@ -258,20 +256,28 @@ Class PrimType Extends Type
 	
 	Method DistanceToType:Int( type:Type ) Override
 	
-		If type=Self Return 0
+		If type.Equals( Self ) Return 0
+		If type.Equals( BoolType ) Return MAX_DISTANCE
+		If type.Equals( VariantType ) Return MAX_DISTANCE
 		
 		Select type
 		Case StringType
 
+			'numeric->string
 			If IsNumeric Return MAX_DISTANCE
 
-		Case CStringClass,WStringClass,Utf8StringClass
+		Case CStringClass
 		
+			'numeric,string->cstring.
 			If Self=StringType Or IsNumeric Return MAX_DISTANCE
 			
 		Default
 		
-			If TCast<PrimType>( type ) Return MAX_DISTANCE
+			'numeric,bool->numeric
+			If IsNumeric Or Self=BoolType
+				Local ptype:=TCast<PrimType>( type )
+				If ptype And ptype.IsNumeric Return MAX_DISTANCE
+			Endif
 		
 		End
 		
@@ -287,6 +293,15 @@ Class PrimType Extends Type
 	
 		If DistanceToType( type )>=0 Return True
 		
+		'variant->any
+		If Self=VariantType Return true
+		
+		'string->numeric
+		If Self=StringType
+			Local ptype:=Cast<PrimType>( type )
+			If ptype And ptype.IsNumeric Return True
+		Endif
+		
 		'integral->enum
 		If IsIntegral And TCast<EnumType>( type ) Return True
 		
@@ -405,9 +420,9 @@ Class ArrayType Extends Type
 	
 	Method DistanceToType:Int( type:Type ) Override
 	
-		If Equals( type ) Return 0
-		
-		If TCast<PrimType>( type )=BoolType Return MAX_DISTANCE
+		If type.Equals( Self ) Return 0
+		If type.Equals( BoolType ) Return MAX_DISTANCE
+		If type.Equals( VariantType ) Return MAX_DISTANCE
 		
 		Return -1
 	End
@@ -467,9 +482,11 @@ Class PointerType Extends Type
 	
 	Method DistanceToType:Int( type:Type ) Override
 	
-		If type=Self Return 0
+		If type.Equals( Self ) Return 0
+		If type.Equals( BoolType ) Return MAX_DISTANCE
+		If type.Equals( VariantType ) Return MAX_DISTANCE
 		
-		If type.Dealias=BoolType Return MAX_DISTANCE
+'		If type.Dealias=BoolType Return MAX_DISTANCE
 		
 		Local ptype:=TCast<PointerType>( type )
 		If Not ptype Return -1
@@ -574,7 +591,9 @@ Class FuncType Extends Type
 	
 	Method DistanceToType:Int( type:Type ) Override
 
-		If Equals( type ) Return 0
+		If type.Equals( Self ) Return 0
+'		If type.Equals( BoolType ) Return MAX_DISTANCE			'NO func->bool yet!
+		If type.Equals( VariantType ) Return MAX_DISTANCE
 		
 '		If type.Dealias Return MAX_DISTANCE
 		

+ 38 - 0
src/mx2cc/value.monkey2

@@ -126,6 +126,11 @@ Class TypeValue Extends Value
 		Return "<"+ttype.ToString()+">"
 	End
 	
+'	Method ToRValue:Value() Override
+'		Throw New SemantEx( "Type '"+ttype.ToString()+"' cannot be converted to a value" )
+'		Return Null
+'	End
+	
 	Method FindValue:Value( ident:String ) Override
 		Local node:=ttype.FindNode( ident )
 		If node Return node.ToValue( Null )
@@ -282,6 +287,8 @@ Class LiteralValue Extends Value
 			Endif
 		Else If ptype=Type.StringType
 			result=value
+		Else If ptype=Type.VariantType
+			Return New UpCastValue( Type.VariantType,Self )
 		Else
 			SemantError( "LiteralValue.UpCast()" )
 		End
@@ -597,3 +604,34 @@ Class PointerValue Extends Value
 	End
 
 End
+
+Class TypeofValue Extends Value
+
+	Field value:Value
+	
+	Method New( value:Value )
+		Self.type=Type.TypeInfoClass
+		Self.value=value
+	End
+	
+	Method ToString:String() Override
+		Return "Typeof("+value.ToString()+")"
+	End
+	
+End
+
+Class TypeofTypeValue Extends Value
+
+	Field ttype:Type
+	
+	Method New( ttype:Type )
+		Self.type=Type.TypeInfoClass
+		Self.ttype=ttype
+	End
+
+	Method ToString:String() Override
+		Return "Typeof<"+ttype.ToString()+">"
+	End
+		
+End
+