etqw-sdk/source/game/script/Script_Exporter.cpp

3766 lines
107 KiB
C++

// Copyright (C) 2007 Id Software, Inc.
//
#include <set>
#include "../precompiled.h"
#pragma hdrstop
#include "../../framework/Licensee.h"
#include "Script_Exporter.h"
#include "Script_Program.h"
#include "Script_Compiler.h"
idCVar g_compiledScriptSafety( "g_compiledScriptSafety", "1", CVAR_BOOL | CVAR_GAME, "enables extra safety checks in exported scripts" );
const char* g_vcProjFileInfo = "<File RelativePath=\"..\\..\\%s\">\n" \
"</File>\n";
const char* g_vcProjFilterStartInfo = "<Filter Name=\"%s\">\n";
const char* g_vcProjFilterEndInfo = "</Filter>\n";
enum cs_fixedHFileType {
CS_FFH_EVENTS,
CS_FFH_EVENTCALLS,
CS_FFH_FUNCTIONWRAPPERS,
CS_FFH_GLOBALFUNCTIONS,
CS_FFH_GLOBALVARIABLES,
CS_FFH_SYSCALLS,
CS_FFH_VIRTUALFUNCTIONS,
CS_FFH_VIRTUALFUNCTIONDEPENDANCIES,
CS_FFH_NUM,
};
const char* g_fixedHFileName[ CS_FFH_NUM ] = {
"src/Generated_Events.h",
"src/Generated_EventCalls.h",
"src/Generated_FunctionWrappers.h",
"src/Generated_GlobalFunctions.h",
"src/Generated_GlobalVariables.h",
"src/Generated_SysCalls.h",
"src/Generated_VirtualFunctions.h",
"src/Generated_VirtualFunctionsDependencies.h",
};
enum cs_fixedCPPFileType {
CS_FFC_EVENTS,
CS_FFC_EVENTCALLS,
CS_FFC_FUNCTIONWRAPPERS,
CS_FFC_GLOBALFUNCTIONS,
CS_FFC_GLOBALVARIABLES,
CS_FFC_SYSCALLS,
CS_FFC_NUM,
};
const char* g_fixedCppFileName[ CS_FFC_NUM ] = {
"src/Generated_Events.cpp",
"src/Generated_EventCalls.cpp",
"src/Generated_FunctionWrappers.cpp",
"src/Generated_GlobalFunctions.cpp",
"src/Generated_GlobalVariables.cpp",
"src/Generated_SysCalls.cpp",
};
void sdScriptExporter::EnterNamespace( const char* name ) {
namespaceDef_t* ns = new namespaceDef_t;
ns->parentNamespace = currentNameSpace;
ns->name = name;
currentNameSpace->namespaces.Alloc() = ns;
currentNameSpace = ns;
RegisterClass( NULL, NULL );
}
void sdScriptExporter::ExitNamespace( void ) {
assert( currentNameSpace->parentNamespace != NULL );
currentNameSpace = currentNameSpace->parentNamespace;
}
void sdScriptExporter::RegisterEventDef( const function_t& f ) {
eventDef_t& e = events.Alloc();
e.name = f.Name();
}
const char* sdScriptExporter::BuildEventName( const char* name ) {
return va( "GeneratedEvent_%s", name );
}
const char* sdScriptExporter::BuildClassName( const idTypeDef* type ) {
if ( type == &type_object ) {
return BASE_COMPILED_SCRIPT_CLASS;
}
return va( "GeneratedClass_%s", type->Name() );
}
const char* sdScriptExporter::BuildGlobalName( const stackVar_t& var ) {
return var.name.c_str();
}
const char* sdScriptExporter::BuildGlobalFunctionName( const function_t* function ) {
return va( "__gf_%s", function->type->Name() );
}
const char* sdScriptExporter::BuildFieldNameByType( etype_t type, etype_t defaultType ) {
switch( type ) {
case ev_string:
return "sdCompiledScriptType_String";
case ev_wstring:
return "sdCompiledScriptType_WString";
case ev_float:
return "sdCompiledScriptType_Float";
case ev_boolean:
return "sdCompiledScriptType_Boolean";
case ev_vector:
return "sdCompiledScriptType_Vector";
case ev_void:
return "void";
case ev_pointer:
return BuildFieldNameByType( defaultType, ev_error );
case ev_object:
return va( "sdCompiledScriptType_Object< %s >", BuildClassName( &type_object ) );
}
assert( false );
// gameLocal.Error( "Unknown type: %s", type->Name() );
return "<invalid>";
}
const char* sdScriptExporter::BuildFieldName( const idTypeDef* type, etype_t defaultType ) {
if ( type->Inherits( &type_object ) ) {
return va( "sdCompiledScriptType_Object< %s >", BuildClassName( type ) );
}
etype_t t = type->Type();
if ( t == ev_pointer ) {
t = type->PointerType()->Type();
}
return BuildFieldNameByType( t, ev_error );
}
const char* sdScriptExporter::BuildClassHeaderName( const idTypeDef* type, bool full ) {
assert( type->Inherits( &type_object ) );
if ( type == &type_object ) {
return BASE_COMPILED_SCRIPT_CLASS_HEADER;
}
if ( full ) {
return va( "src/GeneratedClass_%s.h", type->Name() );
}
return va( "GeneratedClass_%s.h", type->Name() );
}
const char* sdScriptExporter::BuildClassCPPName( const idTypeDef* type, bool full ) {
assert( type->Inherits( &type_object ) );
if ( type == &type_object ) {
return BASE_COMPILED_SCRIPT_CLASS_CPP;
}
if ( full ) {
return va( "src/GeneratedClass_%s.cpp", type->Name() );
}
return va( "GeneratedClass_%s.cpp", type->Name() );
}
int sdScriptExporter::GetVarDefNum( const idVarDef* var ) {
int count = program->GetNumVarDefs();
for ( int i = 0; i < count; i++ ) {
if ( program->GetVarDef( i ) == var ) {
return i;
}
}
return -1;
}
const char* sdScriptExporter::BuildConstantName( int index ) {
return va( "__g_constant%d", index );
}
int sdScriptExporter::AllocConstant( const idVarDef* var ) {
idTypeDef* type = var->TypeDef();
switch ( type->Type() ) {
case ev_string:
case ev_float:
case ev_boolean:
case ev_vector:
break;
default:
return -1;
}
for ( int i = 0; i < constants.Num(); i++ ) {
if ( var == constants[ i ].value ) {
return i;
}
}
int index = constants.Num();
constantDef_t& def = constants.Alloc();
def.value = var;
return index;
}
void sdScriptExporter::AllocGlobal( const idVarDef* var ) {
idStr name = var->Name();
namespaceDef_t* ns = currentNameSpace;
if ( name[ 0 ] == '$' ) {
name = name.Right( name.Length() - 1 );
ns = &globalNameSpace;
}
if ( FindGlobal( ns, var ) != NULL ) {
return;
}
name = "__g_" + name;
stackVar_t& stackVar = *new stackVar_t;
stackVar.name = name;
stackVar.allocated = true;
stackVar.offset = GetVarDefNum( var );
stackVar.type = var->TypeDef();
assert( stackVar.offset != -1 );
ns->globalVars.Alloc() = &stackVar;
if ( var->Type() == ev_vector ) {
stackVar_t& stackVar1 = *new stackVar_t;
stackVar_t& stackVar2 = *new stackVar_t;
stackVar_t& stackVar3 = *new stackVar_t;
stackVar1.name = va( "%s.GetX()", name.c_str() );
stackVar1.allocated = false;
stackVar1.offset = stackVar.offset + 1;
stackVar1.type = &type_float;
stackVar2.name = va( "%s.GetY()", name.c_str() );
stackVar2.allocated = false;
stackVar2.offset = stackVar.offset + 2;
stackVar2.type = &type_float;
stackVar3.name = va( "%s.GetZ()", name.c_str() );
stackVar3.allocated = false;
stackVar3.offset = stackVar.offset + 3;
stackVar3.type = &type_float;
ns->globalVars.Alloc() = &stackVar1;
ns->globalVars.Alloc() = &stackVar2;
ns->globalVars.Alloc() = &stackVar3;
}
}
int sdScriptExporter::FieldSize( const idTypeDef* typeDef ) {
if ( typeDef->Inherits( &type_object ) ) {
return type_object.Size();
}
return typeDef->Size();
}
const char* sdScriptExporter::FindFieldName( const namespaceDef_t* ns, idTypeDef* type, idVarDef* ptr ) {
objectDef_t* objectDef = FindClass( ns, type );
if ( objectDef->superType != NULL ) {
const char* fieldName = FindFieldName( ns, objectDef->superType->type, ptr );
if ( fieldName != NULL ) {
return fieldName;
}
}
int offset = ptr->value.ptrOffset;
if ( offset < objectDef->baseOffset ) {
return NULL;
}
int localOffset = offset - objectDef->baseOffset;
for ( int i = 0; i < objectDef->fields.Num(); i++ ) {
const idVarDef* field = objectDef->fields[ i ];
int size = FieldSize( field->TypeDef()->FieldType() );
if ( localOffset < size ) {
if ( field->TypeDef()->FieldType()->Type() == ev_vector ) {
if ( ptr->TypeDef()->FieldType()->Type() == ev_float ) {
int index = localOffset / 4;
switch ( index ) {
case 0:
return va( "%s.GetX()", field->Name() );
case 1:
return va( "%s.GetY()", field->Name() );
case 2:
return va( "%s.GetZ()", field->Name() );
}
assert( false );
return NULL;
}
}
if ( localOffset != 0 ) {
assert( false );
}
return field->Name();
}
localOffset -= size;
}
return NULL;
}
void sdScriptExporter::WriteFunctionStub( idFile* file, const functionDef_t& funcDef, idTypeDef* object, int baseparm ) {
const function_t* func = funcDef.function;
if ( !object && funcDef.isVirtual ) {
file->Printf( "virtual " );
}
file->Printf( "%s ", BuildFieldName( func->type->ReturnType() ) );
if ( object ) {
file->Printf( "%s::", BuildClassName( object ) );
}
if ( func->def->scope->Type() == ev_namespace && !funcDef.isVirtual ) {
file->Printf( "%s(", BuildGlobalFunctionName( func ) );
} else {
file->Printf( "%s(", func->type->Name() );
}
int count = func->type->NumParameters();
if ( count > baseparm ) {
file->Printf( " " );
for ( int k = baseparm; k < count; k++ ) {
file->Printf( "%s", BuildFieldName( func->type->GetParmType( k ) ) );
const char* parmName = func->type->GetParmName( k );
if ( *parmName != '\0' ) {
file->Printf( " %s", parmName );
}
if ( k != count - 1 ) {
file->Printf( ", " );
}
}
file->Printf( " " );
}
file->Printf( ")" );
}
void sdScriptExporter::WriteThreadCallWrapperClass( idFile* file, const objectDef_t* obj, int index, int baseparm, bool gui ) {
threadDef_t* t = gui ? obj->guiThreadCalls[ index ] : obj->threadCalls[ index ];
PrintTabs( file );
file->Printf( "class sdProcedureCallLocal : public sdProcedureCall {\r\n" );
PrintTabs( file );
file->Printf( "public:\r\n" );
tabCount++;
PrintTabs( file );
file->Printf( "typedef " );
WriteThreadCallType( file, obj, index, baseparm, "callback_t", gui );
file->Printf( ";\r\n" );
PrintTabs( file );
file->Printf( "sdProcedureCallLocal( " );
if ( obj->type != NULL ) {
file->Printf( "%s _object, ", BuildFieldName( obj->type ) );
}
file->Printf( "callback_t _callback" );
int count = t->parms.Num();
for ( int i = baseparm; i < count; i++ ) {
file->Printf( ", %s _parm%d", BuildFieldName( t->parms[ i ] ), i - baseparm );
}
file->Printf( " ) {\r\n" );
tabCount++;
if ( obj->type != NULL ) {
PrintTabs( file );
file->Printf( "object = _object;\r\n" );
}
PrintTabs( file );
file->Printf( "callback = _callback;\r\n" );
for ( int i = baseparm; i < count; i++ ) {
PrintTabs( file );
file->Printf( "parm%d = _parm%d;\r\n", i - baseparm, i - baseparm );
}
tabCount--;
PrintTabs( file );
file->Printf( "}\r\n" );
PrintTabs( file );
file->Printf( "virtual void Go( void ) {\r\n" );
tabCount++;
PrintTabs( file );
if ( obj->type != NULL ) {
file->Printf( "( *object.*callback )" );
} else {
file->Printf( "( *callback )" );
}
file->Printf( "(" );
if ( count > baseparm ) {
file->Printf( " " );
for ( int i = baseparm; i < count; i++ ) {
if ( i != baseparm ) {
file->Printf( ", " );
}
file->Printf( "parm%d", i - baseparm );
}
file->Printf( " " );
}
file->Printf( ");\r\n" );
tabCount--;
PrintTabs( file );
file->Printf( "}\r\n" );
tabCount--;
PrintTabs( file );
file->Printf( "private:\r\n" );
tabCount++;
if ( obj->type != NULL ) {
PrintTabs( file );
file->Printf( "%s object;\r\n", BuildFieldName( obj->type ) );
}
PrintTabs( file );
file->Printf( "callback_t callback;\r\n" );
for ( int i = baseparm; i < count; i++ ) {
PrintTabs( file );
file->Printf( "%s parm%d;\r\n", BuildFieldName( t->parms[ i ] ), i - baseparm );
}
tabCount--;
PrintTabs( file );
file->Printf( "};\r\n" );
}
void sdScriptExporter::WriteThreadCallType( idFile* file, const objectDef_t* obj, int index, int baseparm, const char* name, bool gui ) {
threadDef_t* t = gui ? obj->guiThreadCalls[ index ] : obj->threadCalls[ index ];
file->Printf( "%s ( ", BuildFieldName( t->returnType ) );
if ( obj->type != NULL ) {
file->Printf( "%s::", BuildClassName( obj->type ) );
}
file->Printf( "* %s )(", name );
int count = t->parms.Num();
if ( count > baseparm ) {
file->Printf( " " );
for ( int k = baseparm; k < count; k++ ) {
file->Printf( "%s", BuildFieldName( t->parms[ k ] ) );
if ( k != count - 1 ) {
file->Printf( ", " );
}
}
file->Printf( " " );
}
file->Printf( ")" );
}
void sdScriptExporter::WriteThreadCallStub( idFile* file, const objectDef_t* obj, int index, int baseparm, bool clarify, bool includeName, bool gui ) {
threadDef_t* t = gui ? obj->guiThreadCalls[ index ] : obj->threadCalls[ index ];
file->Printf( "%s ", BuildFieldName( &type_float ) );
if ( obj->type != NULL && clarify ) {
file->Printf( "%s::", BuildClassName( obj->type ) );
}
file->Printf( "Create%sThread%d( ", gui ? "Gui" : "", index );
WriteThreadCallType( file, obj, index, baseparm, "parm0", gui );
if ( includeName ) {
file->Printf( ", const char* name" );
}
int count = t->parms.Num();
if ( count > baseparm ) {
file->Printf( ", " );
for ( int k = baseparm; k < count; k++ ) {
file->Printf( "%s parm%d", BuildFieldName( t->parms[ k ] ), ( k - baseparm ) + 1 );
if ( k != count - 1 ) {
file->Printf( ", " );
}
}
}
file->Printf( " )" );
}
void sdScriptExporter::WriteFunctionStartSpecial( idFile* file, const objectDef_t& cls, const function_t* function ) {
const char* specialFuncs[] = {
"init",
"preinit",
"syncFields",
NULL,
};
for ( int i = 0; ; i++ ) {
if ( specialFuncs[ i ] == NULL ) {
return;
}
if ( idStr::Cmp( function->type->Name(), specialFuncs[ i ] ) == 0 ) {
break;
}
}
for ( const objectDef_t* o = cls.superType; o != NULL; o = o->superType ) {
for ( int i = 0; i < o->functions.Num(); i++ ) {
if ( idStr::Cmp( o->functions[ i ].function->type->Name(), function->type->Name() ) == 0 ) {
PrintTabs( file );
file->Printf( "%s::%s();\r\n", BuildClassName( o->type ), function->type->Name() );
return;
}
}
}
}
int sdScriptExporter::RegisterSysCall( const function_t* function ) {
return RegisterCall( function, 0, sysCalls );
}
int sdScriptExporter::RegisterEventCall( const function_t* function ) {
return RegisterCall( function, 0, eventCalls );
}
int sdScriptExporter::RegisterCall( const function_t* function, int baseParm, idList< callDef_t* >& list ) {
const idTypeDef* funcType = function->type;
for ( int i = 0; i < list.Num(); ) {
if ( funcType->ReturnType() != list[ i ]->returnType ) {
goto next;
}
if ( list[ i ]->parms.Num() != ( funcType->NumParameters() - baseParm ) ) {
goto next;
}
for ( int j = 0; j < list[ i ]->parms.Num(); j++ ) {
if ( funcType->GetParmType( j + baseParm ) != list[ i ]->parms[ j ] ) {
goto next;
}
}
if ( function->eventdef != NULL ) {
assert( list[ i ]->event != NULL );
assert( baseParm == 0 );
if ( function->eventdef->GetReturnType() != list[ i ]->event->GetReturnType() ) {
goto next;
}
if ( list[ i ]->event->GetNumArgs() != function->eventdef->GetNumArgs() ) {
assert( false );
goto next;
}
for ( int j = 0; j < function->eventdef->GetNumArgs(); j++ ) {
if ( function->eventdef->GetArgFormat()[ j ] != list[ i ]->event->GetArgFormat()[ j ] ) {
goto next;
}
}
}
return i;
next:
i++;
}
int index = list.Num();
callDef_t* call = new callDef_t;
list.Alloc() = call;
call->event = function->eventdef;
call->returnType = funcType->ReturnType();
call->parms.SetNum( funcType->NumParameters() - baseParm );
for ( int i = 0; i < funcType->NumParameters() - baseParm; i++ ) {
call->parms[ i ] = funcType->GetParmType( i + baseParm );
}
return index;
}
void sdScriptExporter::RegisterExternalClassCall( functionDef_t& funcDef ) {
int index = RegisterCall( funcDef.function, 1, externalClassCalls );
funcDef.externalCall = externalClassCalls[ index ];
}
void sdScriptExporter::RegisterExternalFunctionCall( functionDef_t& funcDef ) {
int index = RegisterCall( funcDef.function, 0, externalFunctionCalls );
funcDef.externalCall = externalFunctionCalls[ index ];
}
void sdScriptExporter::WriteClass( const namespaceDef_t* ns, objectDef_t& cls ) {
idStr filenameCPP = BuildClassCPPName( cls.type, true );
idStr filenameH = BuildClassHeaderName( cls.type, true );
generatedCppFiles.Alloc() = filenameCPP;
generatedHFiles.Alloc() = filenameH;
idFile* cppFile = fileSystem->OpenFileWrite( filenameCPP.c_str(), "fs_devpath" );
idFile* headerFile = fileSystem->OpenFileWrite( filenameH.c_str(), "fs_devpath" );
idStr className = BuildClassName( cls.type );
idStr guardString = va( "__%s__", filenameH.c_str() );
guardString.Replace( "/", "_" );
guardString.Replace( ".", "_" );
guardString.ToUpper();
idList< const idTypeDef* > dependencies;
for ( int j = 0; j < cls.functions.Num(); j++ ) {
AddDependency( cls.functions[ j ].function, dependencies, false );
}
for ( int j = 0; j < cls.fields.Num(); j++ ) {
AddDependency( cls.fields[ j ]->TypeDef()->FieldType(), dependencies );
}
headerFile->Printf( "#ifndef %s\r\n", guardString.c_str() );
headerFile->Printf( "#define %s\r\n", guardString.c_str() );
headerFile->Printf( "\r\n" );
headerFile->Printf( "#include \"%s\"\r\n", BuildClassHeaderName( cls.type->SuperClass(), false ) );
headerFile->Printf( "#include \"CompiledScript_Types.h\"\r\n" );
headerFile->Printf( "\r\n" );
if ( dependencies.Num() > 0 ) {
headerFile->Printf( "// dependencies\r\n" );
for ( int i = 0; i < dependencies.Num(); i++ ) {
headerFile->Printf( "class %s;\r\n", BuildClassName( dependencies[ i ] ) );
}
headerFile->Printf( "\r\n" );
}
WriteNamespaceEntry( headerFile, ns );
PrintTabs( headerFile );
headerFile->Printf( "class %s : public ", className.c_str() );
idStr baseClassName = BuildClassName( cls.type->SuperClass() );
headerFile->Printf( "%s", baseClassName.c_str() );
headerFile->Printf( " {\r\n" );
PrintTabs( headerFile );
headerFile->Printf( "SD_CS_DECLARE_CLASS( %s );\r\n", className.c_str() );
PrintTabs( headerFile );
headerFile->Printf( "public:\r\n" );
tabCount++;
for ( int j = 0; j < cls.functions.Num(); j++ ) {
PrintTabs( headerFile );
WriteFunctionStub( headerFile, cls.functions[ j ], NULL, 1 );
RegisterExternalClassCall( cls.functions[ j ] );
headerFile->Printf( ";\r\n" );
}
for ( int j = 0; j < cls.threadCalls.Num(); j++ ) {
PrintTabs( headerFile );
WriteThreadCallStub( headerFile, &cls, j, 1, false, true, false );
headerFile->Printf( ";\r\n" );
}
for ( int j = 0; j < cls.guiThreadCalls.Num(); j++ ) {
PrintTabs( headerFile );
WriteThreadCallStub( headerFile, &cls, j, 1, false, true, true );
headerFile->Printf( ";\r\n" );
}
for ( int j = 0; j < cls.fields.Num(); j++ ) {
const idVarDef* var = cls.fields[ j ];
PrintTabs( headerFile );
headerFile->Printf( "%s %s;\r\n", BuildFieldName( var->TypeDef()->FieldType() ), var->Name() );
PrintTabs( headerFile );
headerFile->Printf( "byte* __GetVariable_%s() { return %s.GetPointer(); }\r\n", var->Name(), var->Name() );
}
PrintTabs( headerFile );
headerFile->Printf( "static sdClassFunctionInfo __functionInfo[];\r\n" );
PrintTabs( headerFile );
headerFile->Printf( "static sdClassVariableInfo __variableInfo[];\r\n" );
PrintTabs( headerFile );
headerFile->Printf( "static %s* Allocate( void ) { return new %s; }\r\n", BASE_COMPILED_SCRIPT_CLASS_ALLOCATE, className.c_str() );
PrintTabs( headerFile );
headerFile->Printf( "static sdClassInfo __classInfo;\r\n" );
tabCount--;
PrintTabs( headerFile );
headerFile->Printf( "};\r\n" );
WriteNamespaceExit( headerFile, ns );
headerFile->Printf( "\r\n#endif // %s\r\n", guardString.c_str() );
dependencies.Clear();
for ( int j = 0; j < cls.functions.Num(); j++ ) {
AddDependency( cls.functions[ j ].function, dependencies, true );
}
cppFile->Printf( "\r\n" );
cppFile->Printf( "#include \"Precompiled.h\"\r\n" );
cppFile->Printf( "#pragma hdrstop\r\n\r\n" );
cppFile->Printf( "#include \"Generated_Events.h\"\r\n" );
cppFile->Printf( "#include \"Generated_GlobalVariables.h\"\r\n" );
cppFile->Printf( "#include \"Generated_GlobalFunctions.h\"\r\n" );
cppFile->Printf( "#include \"Generated_SysCalls.h\"\r\n" );
cppFile->Printf( "#include \"Generated_EventCalls.h\"\r\n" );
cppFile->Printf( "#include \"Generated_FunctionWrappers.h\"\r\n" );
cppFile->Printf( "#include \"%s\"\r\n", BuildClassHeaderName( cls.type, false ) );
cppFile->Printf( "\r\n" );
dependencies.Remove( cls.type );
dependencies.Remove( cls.type->SuperClass() );
if ( dependencies.Num() > 0 ) {
cppFile->Printf( "// dependencies\r\n" );
for ( int i = 0; i < dependencies.Num(); i++ ) {
cppFile->Printf( "#include \"%s\"\r\n", BuildClassHeaderName( dependencies[ i ], false ) );
}
cppFile->Printf( "\r\n" );
}
WriteNamespaceEntry( cppFile, ns );
PrintTabs( cppFile );
cppFile->Printf( "SD_CS_IMPLEMENT_CLASS( %s, %s );\r\n", className.c_str(), baseClassName.c_str() );
PrintTabs( cppFile );
cppFile->Printf( "sdClassFunctionInfo %s::__functionInfo[] = {\r\n", className.c_str() );
tabCount++;
for ( int i = 0; i < cls.functions.Num(); i++ ) {
const function_t* func = cls.functions[ i ].function;
callDef_t* wrapper = cls.functions[ i ].externalCall;
int index = externalClassCalls.FindIndex( wrapper );
PrintTabs( cppFile );
cppFile->Printf( "{ \"%s\", &ClassFunctionWrapper%d, ( classFunctionCallback_t )( &%s::%s ), %d, %d },\r\n", func->type->Name(), index, className.c_str(), func->type->Name(), func->type->NumParameters() - 1, func->parmTotal - type_object.Size() );
}
PrintTabs( cppFile );
cppFile->Printf( "{ NULL, NULL },\r\n" );
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "};\r\n" );
PrintTabs( cppFile );
cppFile->Printf( "sdClassVariableInfo %s::__variableInfo[] = {\r\n", className.c_str() );
tabCount++;
for ( int i = 0; i < cls.fields.Num(); i++ ) {
const char* fieldType = NULL;
switch ( cls.fields[ i ]->TypeDef()->FieldType()->Type() ) {
case ev_float:
fieldType = "V_FLOAT";
break;
case ev_boolean:
fieldType = "V_BOOLEAN";
break;
case ev_vector:
fieldType = "V_VECTOR";
break;
case ev_object:
fieldType = "V_OBJECT";
break;
case ev_string:
fieldType = "V_STRING";
break;
case ev_wstring:
fieldType = "V_WSTRING";
break;
default:
assert( false );
break;
}
PrintTabs( cppFile );
cppFile->Printf( "{ \"%s\", %s, ( variableLookup_t )( &%s::__GetVariable_%s ) },\r\n", cls.fields[ i ]->Name(), fieldType, className.c_str(), cls.fields[ i ]->Name() );
}
PrintTabs( cppFile );
cppFile->Printf( "{ NULL, V_NONE, NULL },\r\n" );
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "};\r\n" );
PrintTabs( cppFile );
cppFile->Printf( "sdClassInfo %s::__classInfo = {\r\n", className.c_str() );
tabCount++;
PrintTabs( cppFile );
cppFile->Printf( "\"%s\",\r\n", cls.type->Name() );
PrintTabs( cppFile );
cppFile->Printf( "%s::__functionInfo,\r\n", className.c_str() );
PrintTabs( cppFile );
cppFile->Printf( "%s::__variableInfo,\r\n", className.c_str() );
PrintTabs( cppFile );
if ( cls.superType != NULL ) {
cppFile->Printf( "&%s::__classInfo,\r\n", program->scriptExporter.BuildClassName( cls.superType->type ) );
} else {
cppFile->Printf( "NULL,\r\n" );
}
PrintTabs( cppFile );
cppFile->Printf( "&%s::Allocate,\r\n", className.c_str() );
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "};\r\n" );
for ( int i = 0; i < cls.functions.Num(); i++ ) {
const function_t* func = cls.functions[ i ].function;
PrintTabs( cppFile );
WriteFunctionStub( cppFile, cls.functions[ i ], cls.type, 1 );
cppFile->Printf( " {\r\n" );
tabCount++;
WriteFunctionStartSpecial( cppFile, cls, func );
sdFunctionCompileState* state = new sdFunctionCompileState( &cls.functions[ i ], ns, cppFile, tabCount, program );
state->Run();
delete state;
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "}\r\n" );
cppFile->Printf( "\r\n" );
}
for ( int j = 0; j < cls.threadCalls.Num(); j++ ) {
PrintTabs( cppFile );
WriteThreadCallStub( cppFile, &cls, j, 1, true, true, false );
cppFile->Printf( " {\r\n" );
tabCount++;
WriteThreadCallWrapperClass( cppFile, &cls, j, 1, false );
PrintTabs( cppFile );
cppFile->Printf( "return compilerInterface->AllocThread( this, name, new sdProcedureCallLocal( this, parm0" );
for ( int k = 1; k < cls.threadCalls[ j ]->parms.Num(); k++ ) {
cppFile->Printf( ", parm%d", k );
}
cppFile->Printf( " ) );\r\n" );
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "}\r\n" );
}
for ( int j = 0; j < cls.guiThreadCalls.Num(); j++ ) {
PrintTabs( cppFile );
WriteThreadCallStub( cppFile, &cls, j, 1, true, true, true );
cppFile->Printf( " {\r\n" );
tabCount++;
WriteThreadCallWrapperClass( cppFile, &cls, j, 1, true );
PrintTabs( cppFile );
cppFile->Printf( "return compilerInterface->AllocGuiThread( this, name, new sdProcedureCallLocal( this, parm0" );
for ( int k = 1; k < cls.guiThreadCalls[ j ]->parms.Num(); k++ ) {
cppFile->Printf( ", parm%d", k );
}
cppFile->Printf( " ) );\r\n" );
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "}\r\n" );
}
WriteNamespaceExit( cppFile, ns );
fileSystem->CloseFile( headerFile );
fileSystem->CloseFile( cppFile );
}
void sdScriptExporter::WriteNamespaceTitle( idFile* file, const namespaceDef_t* ns ) {
file->Printf( "namespace __ns_%s", ns->name.c_str() );
}
void sdScriptExporter::WriteNamespaceScope( idFile* file, const namespaceDef_t* ns ) {
idList< const namespaceDef_t* > list;
while ( ns ) {
list.Insert( ns );
ns = ns->parentNamespace;
}
for ( int i = 0; i < list.Num(); i++ ) {
if ( list[ i ]->name.Length() <= 0 ) {
continue;
}
WriteNamespaceTitle( file, list[ i ] );
file->Printf( "::" );
}
}
void sdScriptExporter::WriteNamespaceEntry( idFile* file, const namespaceDef_t* ns ) {
idList< const namespaceDef_t* > list;
while ( ns ) {
list.Insert( ns );
ns = ns->parentNamespace;
}
for ( int i = 0; i < list.Num(); i++ ) {
if ( list[ i ]->name.Length() <= 0 ) {
continue;
}
PrintTabs( file );
WriteNamespaceTitle( file, list[ i ] );
file->Printf( " {\r\n" );
tabCount++;
}
}
void sdScriptExporter::WriteNamespaceExit( idFile* file, const namespaceDef_t* ns ) {
idList< const namespaceDef_t* > list;
while ( ns ) {
list.Insert( ns );
ns = ns->parentNamespace;
}
for ( int i = 0; i < list.Num(); i++ ) {
if ( list[ i ]->name.Length() <= 0 ) {
continue;
}
tabCount--;
PrintTabs( file );
file->Printf( "}\r\n" );
}
}
void sdScriptExporter::PrintTabs( idFile* file ) {
for ( int i = 0; i < tabCount; i++ ) {
file->Printf( "\t" );
}
}
void sdScriptExporter::WriteGlobalVariablesHeader( idFile* file, const namespaceDef_t* ns ) {
if ( ns->name.Length() > 0 ) {
PrintTabs( file );
WriteNamespaceTitle( file, ns );
file->Printf( " {\r\n" );
tabCount++;
}
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
WriteGlobalVariablesHeader( file, ns->namespaces[ i ] );
}
for ( int i = 0; i < ns->globalVars.Num(); i++ ) {
if ( !ns->globalVars[ i ]->allocated ) {
continue;
}
PrintTabs( file );
file->Printf( "extern " );
file->Printf( "%s ", BuildFieldName( ns->globalVars[ i ]->type ) );
file->Printf( "%s", BuildGlobalName( *ns->globalVars[ i ] ) );
file->Printf( ";\r\n" );
}
if ( ns->name.Length() > 0 ) {
tabCount--;
PrintTabs( file );
file->Printf( "}\r\n" );
}
}
void sdScriptExporter::WriteGlobalVariablesCPP( idFile* file, const namespaceDef_t* ns ) {
if ( ns->name.Length() > 0 ) {
PrintTabs( file );
WriteNamespaceTitle( file, ns );
file->Printf( " {\r\n" );
tabCount++;
}
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
WriteGlobalVariablesCPP( file, ns->namespaces[ i ] );
}
for ( int i = 0; i < ns->globalVars.Num(); i++ ) {
if ( !ns->globalVars[ i ]->allocated ) {
continue;
}
PrintTabs( file );
file->Printf( "%s ", BuildFieldName( ns->globalVars[ i ]->type ) );
file->Printf( "%s", BuildGlobalName( *ns->globalVars[ i ] ) );
file->Printf( ";\r\n" );
}
if ( ns->name.Length() > 0 ) {
tabCount--;
PrintTabs( file );
file->Printf( "}\r\n" );
}
}
void sdScriptExporter::AddDependency( const function_t* function, idList< const idTypeDef* >& dependencies, bool contents ) {
int count = function->type->NumParameters();
if ( !contents ) {
AddDependency( function->type->ReturnType(), dependencies );
for ( int i = 0; i < count; i++ ) {
AddDependency( function->type->GetParmType( i ), dependencies );
}
} else {
for ( int i = function->firstStatement; i < function->firstStatement + function->numStatements; i++ ) {
statement_t& statement = program->GetStatement( i );
if ( statement.a != NULL ) {
AddDependency( statement.a->TypeDef(), dependencies );
}
if ( statement.b != NULL ) {
AddDependency( statement.b->TypeDef(), dependencies );
}
if ( statement.c != NULL ) {
AddDependency( statement.c->TypeDef(), dependencies );
}
}
}
}
void sdScriptExporter::AddDependency( const idTypeDef* type, idList< const idTypeDef* >& dependencies ) {
if ( !type->Inherits( &type_object ) ) {
return;
}
dependencies.AddUnique( type );
}
void sdScriptExporter::FindGlobalFunctionDependencies( namespaceDef_t* ns, idList< const idTypeDef* >& dependencies ) {
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
FindGlobalFunctionDependencies( ns->namespaces[ i ], dependencies );
}
objectDef_t* globalObj = ns->classes[ 0 ];
for ( int i = 0; i < globalObj->functions.Num(); i++ ) {
AddDependency( globalObj->functions[ i ].function, dependencies, false );
}
}
void sdScriptExporter::FindGlobalVariablesDependencies( namespaceDef_t* ns, idList< const idTypeDef* >& dependencies ) {
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
FindGlobalVariablesDependencies( ns->namespaces[ i ], dependencies );
}
for ( int i = 0; i < ns->globalVars.Num(); i++ ) {
AddDependency( ns->globalVars[ i ]->type, dependencies );
}
}
void sdScriptExporter::WriteGlobalVariables( void ) {
idFile* headerFile = fileSystem->OpenFileWrite( g_fixedHFileName[ CS_FFH_GLOBALVARIABLES ], "fs_devpath" );
headerFile->Printf( "#ifndef __GENERATED_GLOBALVARIABLES_H__\r\n" );
headerFile->Printf( "#define __GENERATED_GLOBALVARIABLES_H__\r\n" );
headerFile->Printf( "\r\n" );
headerFile->Printf( "#include \"CompiledScript_Types.h\"\r\n" );
headerFile->Printf( "\r\n" );
idList< const idTypeDef* > dependencies;
FindGlobalVariablesDependencies( &globalNameSpace, dependencies );
if ( dependencies.Num() > 0 ) {
headerFile->Printf( "// dependencies\r\n" );
for ( int i = 0; i < dependencies.Num(); i++ ) {
headerFile->Printf( "class %s;\r\n", BuildClassName( dependencies[ i ] ) );
}
headerFile->Printf( "\r\n" );
}
WriteGlobalVariablesHeader( headerFile, &globalNameSpace );
for ( int i = 0; i < constants.Num(); i++ ) {
switch ( constants[ i ].value->Type() ) {
case ev_string:
headerFile->Printf( "extern const sdCompiledScriptType_String %s;\r\n", BuildConstantName( i ) );
break;
case ev_float:
headerFile->Printf( "extern const sdCompiledScriptType_Float %s;\r\n", BuildConstantName( i ) );
break;
case ev_boolean:
headerFile->Printf( "extern const sdCompiledScriptType_Boolean %s;\r\n", BuildConstantName( i ) );
break;
case ev_vector:
headerFile->Printf( "extern const sdCompiledScriptType_Vector %s;\r\n", BuildConstantName( i ) );
break;
}
}
headerFile->Printf( "#endif // __GENERATED_GLOBALVARIABLES_H__\r\n" );
fileSystem->CloseFile( headerFile );
idFile* cppFile = fileSystem->OpenFileWrite( g_fixedCppFileName[ CS_FFC_GLOBALVARIABLES ], "fs_devpath" );
cppFile->Printf( "\r\n" );
cppFile->Printf( "#include \"Precompiled.h\"\r\n" );
cppFile->Printf( "#pragma hdrstop\r\n\r\n" );
cppFile->Printf( "#include \"Generated_GlobalVariables.h\"\r\n" );
cppFile->Printf( "\r\n" );
WriteGlobalVariablesCPP( cppFile, &globalNameSpace );
for ( int i = 0; i < constants.Num(); i++ ) {
switch ( constants[ i ].value->Type() ) {
case ev_string: {
idStr temp = constants[ i ].value->value.stringPtr;
temp.Replace( "\\", "\\\\" );
temp.Replace( "\r", "\\r" );
temp.Replace( "\n", "\\n" );
temp.Replace( "\t", "\\t" );
temp.Replace( "\"", "\\\"" );
cppFile->Printf( "const sdCompiledScriptType_String %s( \"%s\" );\r\n", BuildConstantName( i ), temp.c_str() );
break;
}
case ev_float:
cppFile->Printf( "const sdCompiledScriptType_Float %s( %ff );\r\n", BuildConstantName( i ), *constants[ i ].value->value.floatPtr );
break;
case ev_boolean:
cppFile->Printf( "const sdCompiledScriptType_Boolean %s( %s );\r\n", BuildConstantName( i ), *constants[ i ].value->value.intPtr ? "true" : "false" );
break;
case ev_vector: {
idVec3& v = *constants[ i ].value->value.vectorPtr;
cppFile->Printf( "const sdCompiledScriptType_Vector %s( %ff, %ff, %ff );\r\n", BuildConstantName( i ), v[ 0 ], v[ 1 ], v[ 2 ] );
break;
}
}
}
fileSystem->CloseFile( cppFile );
}
void sdScriptExporter::WriteNamespaceFunctions( const namespaceDef_t* ns ) {
idFile* headerFile = fileSystem->OpenFileWrite( g_fixedHFileName[ CS_FFH_GLOBALFUNCTIONS ], "fs_devpath" );
headerFile->Printf( "#ifndef __GENERATED_GLOBALFUNCTIONS_H__\r\n" );
headerFile->Printf( "#define __GENERATED_GLOBALFUNCTIONS_H__\r\n" );
headerFile->Printf( "\r\n" );
headerFile->Printf( "#include \"CompiledScript_Types.h\"\r\n" );
headerFile->Printf( "\r\n" );
headerFile->Printf( "class sdCompiledScript_Class;\r\n" );
headerFile->Printf( "\r\n" );
idList< const idTypeDef* > dependencies;
FindGlobalFunctionDependencies( &globalNameSpace, dependencies );
if ( dependencies.Num() > 0 ) {
headerFile->Printf( "// dependencies\r\n" );
for ( int i = 0; i < dependencies.Num(); i++ ) {
headerFile->Printf( "class %s;\r\n", BuildClassName( dependencies[ i ] ) );
}
headerFile->Printf( "\r\n" );
}
idFile* cppFile = fileSystem->OpenFileWrite( g_fixedCppFileName[ CS_FFC_GLOBALFUNCTIONS ], "fs_devpath" );
cppFile->Printf( "\r\n" );
cppFile->Printf( "#include \"Precompiled.h\"\r\n" );
cppFile->Printf( "#pragma hdrstop\r\n\r\n" );
cppFile->Printf( "#include \"Generated_GlobalVariables.h\"\r\n" );
cppFile->Printf( "#include \"Generated_GlobalFunctions.h\"\r\n" );
cppFile->Printf( "#include \"Generated_Events.h\"\r\n" );
cppFile->Printf( "#include \"Generated_SysCalls.h\"\r\n" );
cppFile->Printf( "#include \"Generated_EventCalls.h\"\r\n" );
cppFile->Printf( "#include \"CompiledScript_Class.h\"\r\n" );
WriteNamespaceClassIncludes( ns, cppFile );
cppFile->Printf( "\r\n" );
WriteNamespaceFunctions( ns, headerFile, cppFile );
WriteFunctionWrappers( cppFile );
WriteNamespaceFunctionInfo( ns, cppFile );
cppFile->Printf( "void sdCompiledScript_Class::InitClasses() {\r\n" );
tabCount++;
WriteNamespaceClassInit( ns, cppFile );
tabCount--;
cppFile->Printf( "}\r\n" );
cppFile->Printf( "void sdCompiledScript_Class::InitFunctions() {\r\n" );
tabCount++;
WriteNamespaceFunctionInit( ns, cppFile );
tabCount--;
cppFile->Printf( "}\r\n" );
fileSystem->CloseFile( cppFile );
headerFile->Printf( "\r\n" );
headerFile->Printf( "#endif // __GENERATED_GLOBALFUNCTIONS_H__\r\n" );
fileSystem->CloseFile( headerFile );
}
void sdScriptExporter::WriteNamespaceClassIncludes( const namespaceDef_t* ns, idFile* cppFile ) {
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
WriteNamespaceClassIncludes( ns->namespaces[ i ], cppFile );
}
for ( int i = 1; i < ns->classes.Num(); i++ ) {
cppFile->Printf( "#include \"%s\"\r\n", BuildClassHeaderName( ns->classes[ i ]->type, false ) );
}
}
void sdScriptExporter::WriteNamespaceClassInit( const namespaceDef_t* ns, idFile* cppFile ) {
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
WriteNamespaceClassInit( ns->namespaces[ i ], cppFile );
}
if ( ns->classes.Num() > 1 ) {
WriteNamespaceEntry( cppFile, ns );
for ( int i = 1; i < ns->classes.Num(); i++ ) {
PrintTabs( cppFile );
cppFile->Printf( "sdCompiledScript_Class::AddClassInfo( &%s::__classInfo );\r\n", BuildClassName( ns->classes[ i ]->type ) );
}
WriteNamespaceExit( cppFile, ns );
}
}
void sdScriptExporter::WriteNamespaceFunctionInfo( const namespaceDef_t* ns, idFile* cppFile ) {
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
WriteNamespaceFunctionInfo( ns->namespaces[ i ], cppFile );
}
objectDef_t& info = *ns->classes[ 0 ];
for ( int i = 0; i < info.functions.Num(); i++ ) {
PrintTabs( cppFile );
const char* name = info.functions[ i ].function->type->Name();
cppFile->Printf( "sdFunctionInfo __functionInfo_%s = {", name );
cppFile->Printf( " \"%s\", ", name );
int index = externalFunctionCalls.FindIndex( info.functions[ i ].externalCall );
cppFile->Printf( " &GlobalFunctionWrapper%d, ", index );
cppFile->Printf( " ( functionCallback_t )( &" );
WriteNamespaceScope( cppFile, ns );
cppFile->Printf( "%s ) };\r\n", BuildGlobalFunctionName( info.functions[ i ].function ) );
}
}
void sdScriptExporter::WriteNamespaceFunctionInit( const namespaceDef_t* ns, idFile* cppFile ) {
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
WriteNamespaceFunctionInit( ns->namespaces[ i ], cppFile );
}
objectDef_t& info = *ns->classes[ 0 ];
for ( int i = 0; i < info.functions.Num(); i++ ) {
PrintTabs( cppFile );
cppFile->Printf( "sdCompiledScript_Class::AddFunctionInfo( &__functionInfo_%s );\r\n", info.functions[ i ].function->type->Name() );
}
}
void sdScriptExporter::WriteNamespaceFunctions( const namespaceDef_t* ns, idFile* headerFile, idFile* cppFile ) {
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
WriteNamespaceFunctions( ns->namespaces[ i ], headerFile, cppFile );
}
objectDef_t& info = *ns->classes[ 0 ];
WriteNamespaceEntry( headerFile, ns );
for ( int i = 0; i < info.functions.Num(); i++ ) {
PrintTabs( headerFile );
WriteFunctionStub( headerFile, info.functions[ i ], NULL, 0 );
headerFile->Printf( ";\r\n" );
RegisterExternalFunctionCall( info.functions[ i ] );
}
for ( int j = 0; j < info.threadCalls.Num(); j++ ) {
PrintTabs( headerFile );
WriteThreadCallStub( headerFile, &info, j, 0, false, false, false );
headerFile->Printf( ";\r\n" );
}
for ( int j = 0; j < info.guiThreadCalls.Num(); j++ ) {
PrintTabs( headerFile );
WriteThreadCallStub( headerFile, &info, j, 0, false, false, true );
headerFile->Printf( ";\r\n" );
}
WriteNamespaceExit( headerFile, ns );
WriteNamespaceEntry( cppFile, ns );
for ( int i = 0; i < info.functions.Num(); i++ ) {
PrintTabs( cppFile );
WriteFunctionStub( cppFile, info.functions[ i ], NULL, 0 );
cppFile->Printf( " {\r\n" );
tabCount++;
sdFunctionCompileState* state = new sdFunctionCompileState( &info.functions[ i ], ns, cppFile, tabCount, program );
state->Run();
delete state;
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "}\r\n" );
}
for ( int j = 0; j < info.threadCalls.Num(); j++ ) {
PrintTabs( cppFile );
WriteThreadCallStub( cppFile, &info, j, 0, false, false, false );
cppFile->Printf( " {\r\n" );
tabCount++;
WriteThreadCallWrapperClass( cppFile, &info, j, 0, false );
PrintTabs( cppFile );
cppFile->Printf( "return compilerInterface->AllocThread( new sdProcedureCallLocal( parm0" );
for ( int k = 0; k < info.threadCalls[ j ]->parms.Num(); k++ ) {
cppFile->Printf( ", parm%d", k + 1 );
}
cppFile->Printf( " ) );\r\n" );
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "}\r\n" );
}
for ( int j = 0; j < info.guiThreadCalls.Num(); j++ ) {
PrintTabs( cppFile );
WriteThreadCallStub( cppFile, &info, j, 0, false, false, true );
cppFile->Printf( " {\r\n" );
tabCount++;
WriteThreadCallWrapperClass( cppFile, &info, j, 0, true );
PrintTabs( cppFile );
cppFile->Printf( "return compilerInterface->AllocGuiThread( new sdProcedureCallLocal( parm0" );
for ( int k = 0; k < info.guiThreadCalls[ j ]->parms.Num(); k++ ) {
cppFile->Printf( ", parm%d", k + 1 );
}
cppFile->Printf( " ) );\r\n" );
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "}\r\n" );
}
WriteNamespaceExit( cppFile, ns );
}
int sdScriptExporter::FindThreadCall( const objectDef_t& obj, const function_t* function, bool guithreadcall ) {
const idList< threadDef_t* >& list = guithreadcall ? obj.guiThreadCalls : obj.threadCalls;
for ( int i = 0; i < list.Num(); i++ ) {
if ( list[ i ]->returnType != function->type->ReturnType() ) {
continue;
}
if ( function->type->NumParameters() != list[ i ]->parms.Num() ) {
continue;
}
int j;
for ( j = 0; j < list[ i ]->parms.Num(); j++ ) {
if ( list[ i ]->parms[ j ] != function->type->GetParmType( j ) ) {
break;
}
}
if ( j < list[ i ]->parms.Num() ) {
continue;
}
return i;
}
return -1;
}
void sdScriptExporter::RegisterClassThreadCall( idTypeDef* type, const function_t* function, bool guithreadcall ) {
namespaceDef_t* ns = currentNameSpace;
if ( type == NULL ) {
ns = &globalNameSpace;
}
objectDef_t* o = FindClass( ns, type );
assert( o != NULL );
int index = FindThreadCall( *o, function, guithreadcall );
if ( index == -1 ) {
threadDef_t* t = new threadDef_t;
t->returnType = function->type->ReturnType();
for ( int i = 0; i < function->type->NumParameters(); i++ ) {
t->parms.Alloc() = function->type->GetParmType( i );
}
if ( guithreadcall ) {
o->guiThreadCalls.Alloc() = t;
} else {
o->threadCalls.Alloc() = t;
}
}
}
void sdScriptExporter::Finish( void ) {
idFile* file;
file = fileSystem->OpenFileWrite( g_fixedCppFileName[ CS_FFC_EVENTS ], "fs_devpath" );
if ( file != NULL ) {
file->Printf( "\r\n" );
file->Printf( "#include \"Precompiled.h\"\r\n" );
file->Printf( "#pragma hdrstop\r\n\r\n" );
file->Printf( "#include \"Generated_Events.h\"\r\n" );
file->Printf( "\r\n" );
for ( int i = 0; i < events.Num(); i++ ) {
idStr eventName = BuildEventName( events[ i ].name );
file->Printf( "sdCompiledScript_Event %s( \"%s\" );\r\n", eventName.c_str(), events[ i ].name.c_str() );
}
file->Printf( "\r\n" );
fileSystem->CloseFile( file );
file = NULL;
}
file = fileSystem->OpenFileWrite( g_fixedHFileName[ CS_FFH_EVENTS ], "fs_devpath" );
if ( file != NULL ) {
file->Printf( "\r\n" );
file->Printf( "#ifndef __GENERATED_EVENTS_H__\r\n" );
file->Printf( "#define __GENERATED_EVENTS_H__\r\n" );
file->Printf( "#include \"CompiledScript_Event.h\"\r\n" );
file->Printf( "\r\n" );
for ( int i = 0; i < events.Num(); i++ ) {
idStr eventName = BuildEventName( events[ i ].name );
file->Printf( "extern sdCompiledScript_Event %s;\r\n", eventName.c_str(), events[ i ].name.c_str() );
}
file->Printf( "\r\n" );
file->Printf( "#endif // __GENERATED_EVENTS_H__\r\n" );
fileSystem->CloseFile( file );
file = NULL;
}
WriteVirtualFunctions();
WriteNamespaceFunctions( &globalNameSpace );
WriteNamespaceClasses( &globalNameSpace );
WriteGlobalVariables();
WriteClassFunctionWrappers();
WriteSysCalls();
WriteEventCalls();
WriteBuildVersion();
WriteProjectFile();
}
extern int ENGINE_SRC_REVISION;
extern int ENGINE_MEDIA_REVISION;
void sdScriptExporter::WriteBuildVersion( void ) {
idFile* buildVersionFile = fileSystem->OpenFileWrite( "src/base/BuildVersion.cpp", "fs_devpath" );
if ( buildVersionFile == NULL ) {
gameLocal.Warning( "Failed To Write Version File" );
return;
}
buildVersionFile->Printf( "#include \"Precompiled.h\"\r\n" );
buildVersionFile->Printf( "#pragma hdrstop\r\n\r\n" );
buildVersionFile->Printf( "int ENGINE_VERSION_MAJOR = %d;\r\n", ENGINE_VERSION_MAJOR );
buildVersionFile->Printf( "int ENGINE_VERSION_MINOR = %d;\r\n", ENGINE_VERSION_MINOR );
buildVersionFile->Printf( "int ENGINE_SRC_REVISION = %d;\r\n", ENGINE_SRC_REVISION );
buildVersionFile->Printf( "int ENGINE_MEDIA_REVISION = %d;\r\n", ENGINE_MEDIA_REVISION );
fileSystem->CloseFile( buildVersionFile );
}
void sdScriptExporter::WriteProjectFile( void ) {
// ASM
WriteXCodeProjectFile();
const char *project_basename = "src/base/CompiledScript.vcproj.base";
idFile* projectBaseFile = fileSystem->OpenFileRead( project_basename );
if ( projectBaseFile == NULL ) {
// si_pure or SD_RESTRICTED_FILESYSTEM might screw you here
gameLocal.Warning( "Failed to load %s - skipping project file generation", project_basename );
return;
}
int length = projectBaseFile->Length();
idStr temp;
temp.Fill( '\0', length );
projectBaseFile->Read( &temp[ 0 ], length );
fileSystem->CloseFile( projectBaseFile );
for ( int i = 0; i < CS_FFC_NUM; i++ ) {
generatedCppFiles.Alloc() = g_fixedCppFileName[ i ];
}
for ( int i = 0; i < CS_FFH_NUM; i++ ) {
generatedHFiles.Alloc() = g_fixedHFileName[ i ];
}
idStr replaceBlock;
replaceBlock += va( g_vcProjFilterStartInfo, "Source Files" );
for ( int i = 0; i < generatedCppFiles.Num(); i++ ) {
generatedCppFiles[ i ].SlashesToBackSlashes();
replaceBlock += va( g_vcProjFileInfo, generatedCppFiles[ i ].c_str() );
}
replaceBlock += g_vcProjFilterEndInfo;
replaceBlock += va( g_vcProjFilterStartInfo, "Header Files" );
for ( int i = 0; i < generatedHFiles.Num(); i++ ) {
generatedHFiles[ i ].SlashesToBackSlashes();
replaceBlock += va( g_vcProjFileInfo, generatedHFiles[ i ].c_str(), "" );
}
replaceBlock += g_vcProjFilterEndInfo;
temp.Replace( "$INSERTTEXTHERE$", replaceBlock.c_str() );
idFile* projectBaseOutput = fileSystem->OpenFileWrite( "src/base/CompiledScript.vcproj", "fs_devpath" );
if ( projectBaseOutput == NULL ) {
return;
}
projectBaseOutput->Write( temp.c_str(), temp.Length() );
fileSystem->CloseFile( projectBaseOutput );
sdStringBuilder_Heap src;
sdStringBuilder_Heap dest;
idFileList* dependencies = fileSystem->ListFiles( "src/base", ".*" );
for( int i = 0; i < dependencies->GetNumFiles(); i++ ) {
src = fileSystem->BuildOSPath( fileSystem->GetBasePath(), fileSystem->GetGamePath(),va( "src/base/%s", dependencies->GetFile( i ) ) );
dest = fileSystem->BuildOSPath( cvarSystem->GetCVarString( "fs_devpath" ), fileSystem->GetGamePath(), va( "src/base/%s", dependencies->GetFile( i ) ) );
if( idStr::Cmp( src.c_str(), dest.c_str() ) == 0 ) {
continue;
}
fileSystem->CopyFile( src.c_str(), dest.c_str() );
}
fileSystem->FreeFileList( dependencies );
}
struct PBXFile
{
static unsigned long long lastUsed;
idStr filename;
idStr file_reference;
idStr build_reference;
PBXFile() : filename(""), file_reference(""), build_reference("") {}
PBXFile(const PBXFile& in_file) : filename(in_file.filename),
file_reference(in_file.file_reference), build_reference(in_file.build_reference) {}
PBXFile operator=(const PBXFile& other)
{
filename = other.filename;
file_reference = other.file_reference;
build_reference = other.build_reference;
return *this;
}
PBXFile(const char* new_filename) : filename(new_filename)
{
unsigned long fileHash = ++lastUsed;
unsigned long buildFileHash = ++lastUsed;
sprintf(file_reference, "%llX", fileHash);
file_reference.CapLength(24);
sprintf(build_reference, "%llX", buildFileHash);
build_reference.CapLength(24);
}
};
unsigned long long PBXFile::lastUsed = 0xA6F06A190CB4529ELL;
void sdScriptExporter::WriteXCodeProjectFile( void ) {
const char *project_basename = "src/compiledscript.xcodeproj/project.pbxproj.base";
idFile* projectBaseFile = fileSystem->OpenFileRead( project_basename );
if ( projectBaseFile == NULL ) {
// si_pure or SD_RESTRICTED_FILESYSTEM might screw you here
gameLocal.Warning( "Failed to load %s - skipping project file generation", project_basename );
return;
}
int length = projectBaseFile->Length();
idStr temp;
temp.Fill( '\0', length );
projectBaseFile->Read( &temp[ 0 ], length );
fileSystem->CloseFile( projectBaseFile );
for ( int i = 0; i < CS_FFC_NUM; i++ ) {
generatedCppFiles.Alloc() = g_fixedCppFileName[ i ];
}
for ( int i = 0; i < CS_FFH_NUM; i++ ) {
generatedHFiles.Alloc() = g_fixedHFileName[ i ];
}
idList< PBXFile > projectCPPFiles;
idList< PBXFile > projectHFiles;
for ( int i = 0; i < generatedCppFiles.Num(); i++ ) {
int index = projectCPPFiles.Append( PBXFile( generatedCppFiles[ i ] ) );
projectCPPFiles[ index ].filename.StripPath();
}
for ( int i = 0; i < generatedHFiles.Num(); i++ ) {
int index = projectHFiles.Append( PBXFile( generatedHFiles[ i ] ) );
projectHFiles[ index ].filename.StripPath();
}
idStr PBXBuildFileReplaceString;
for ( int i = 0; i < projectCPPFiles.Num(); i++ ) {
PBXBuildFileReplaceString+= "\t" + projectCPPFiles[ i ].build_reference +
" = {isa = PBXBuildFile; fileRef = " + projectCPPFiles[ i ].file_reference + ";};\n";
}
idStr PBXFileReferenceReplaceString;
for ( int i = 0; i < projectCPPFiles.Num(); i++ ) {
PBXFileReferenceReplaceString+= "\t" + projectCPPFiles[ i ].file_reference +
" = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = " +
projectCPPFiles[ i ].filename + "; path = " + projectCPPFiles[ i ].filename + "; sourceTree = \"<group>\"; };\n";
}
for ( int i = 0; i < projectHFiles.Num(); i++ ) {
PBXFileReferenceReplaceString+= "\t" + projectHFiles[ i ].file_reference +
" = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = " +
projectHFiles[ i ].filename + "; path = " + projectHFiles[ i ].filename + "; sourceTree = \"<group>\"; };\n";
}
idStr PBXFileSourceReferences;
for ( int i = 0; i < projectCPPFiles.Num(); i++ ) {
PBXFileSourceReferences+= "\t" + projectCPPFiles[ i ].file_reference + ",\n";
}
idStr PBXFileHeaderReferences;
for ( int i = 0; i < projectHFiles.Num(); i++ ) {
PBXFileHeaderReferences+= "\t" + projectHFiles[ i ].file_reference + ",\n";
}
idStr PBXBuildPhase;
for ( int i = 0; i < projectCPPFiles.Num(); i++ ) {
PBXBuildPhase+= "\t" + projectCPPFiles[ i ].build_reference + ",\n";
}
temp.Replace( "$INSERTPBXBUILDFILESHERE$", PBXBuildFileReplaceString.c_str() );
temp.Replace( "$INSERTPBXFILEREFERENCESHERE$", PBXFileReferenceReplaceString.c_str() );
temp.Replace( "$INSERTSOURCEREFERENCESHERE$", PBXFileSourceReferences.c_str() );
temp.Replace( "$INSERTHEADERREFERENCESHERE$", PBXFileHeaderReferences.c_str() );
temp.Replace( "$INSERTBUILDPHASEHERE$", PBXBuildPhase.c_str() );
fileSystem->CreateOSPath( "src/compiledscript.xcodeproj/" );
idFile* projectBaseOutput = fileSystem->OpenFileWrite( "src/compiledscript.xcodeproj/project.pbxproj", "fs_devpath" );
if ( projectBaseOutput == NULL ) {
return;
}
projectBaseOutput->Write( temp.c_str(), temp.Length() );
fileSystem->CloseFile( projectBaseOutput );
const char *plist_basename = "src/compiledscript.so-Info.plist.base";
idFile* plistBaseFile = fileSystem->OpenFileRead( plist_basename );
if ( plistBaseFile == NULL ) {
// si_pure or SD_RESTRICTED_FILESYSTEM might screw you here
gameLocal.Warning( "Failed to load %s", plist_basename );
return;
}
length = plistBaseFile->Length();
temp.Fill( '\0', length );
plistBaseFile->Read( &temp[ 0 ], length );
fileSystem->CloseFile( plistBaseFile );
idFile* plistBaseOutput = fileSystem->OpenFileWrite( "src/compiledscript.so-Info.plist", "fs_devpath" );
if ( plistBaseOutput == NULL ) {
return;
}
plistBaseOutput->Write( temp.c_str(), temp.Length() );
fileSystem->CloseFile( plistBaseOutput );
// PBXBuildFile: (INSERTPBXBUILDFILESHERE)
// 96F06A1A0CB452A50010D225 /* Generated_EventCalls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96F065D40CB448CE0010D225 /* Generated_EventCalls.cpp */; };
// PBXFileReference: (INSERTPBXFILEREFERENCESHERE)
// 96F065D40CB448CE0010D225 /* Generated_EventCalls.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Generated_EventCalls.cpp; path = Script/Generated_EventCalls.cpp; sourceTree = "<group>"; };
// 96F065D50CB448CE0010D225 /* Generated_EventCalls.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Generated_EventCalls.h; path = Script/Generated_EventCalls.h; sourceTree = "<group>"; };
// Source references: (INSERTSOURCEREFERENCESHERE)
// 96F0671C0CB448CE0010D225 /* GeneratedClass_task_deployable_disable.cpp */,
// Header references: (INSERTHEADERREFERENCESHERE)
// 96F066FF0CB448CE0010D225 /* GeneratedClass_structure_cc.h */,
// Build phase: (INSERTBUILDPHASEHERE)
// 96F06A1A0CB452A50010D225 /* Generated_EventCalls.cpp in Sources */,
}
void sdScriptExporter::WriteSysCalls( void ) {
idList< const idTypeDef* > dependencies;
idFile* headerFile = fileSystem->OpenFileWrite( g_fixedHFileName[ CS_FFH_SYSCALLS ], "fs_devpath" );
headerFile->Printf( "#ifndef __GENERATED_SYSCALLS_H__\r\n" );
headerFile->Printf( "#define __GENERATED_SYSCALLS_H__\r\n\r\n" );
for ( int i = 0; i < sysCalls.Num(); i++ ) {
callDef_t* t = sysCalls[ i ];
headerFile->Printf( "%s SysCall%d( const sdCompiledScript_Event& _event", BuildFieldName( t->returnType ), i );
if ( t->parms.Num() > 0 ) {
headerFile->Printf( ", " );
for ( int j = 0; j < t->parms.Num(); j++ ) {
headerFile->Printf( "const %s& parm%d", BuildFieldName( t->parms[ j ] ), j );
if ( j != t->parms.Num() - 1 ) {
headerFile->Printf( ", " );
}
}
}
headerFile->Printf( " );\r\n" );
AddDependency( t->returnType, dependencies );
for ( int j = 0; j < t->parms.Num(); j++ ) {
AddDependency( t->parms[ j ], dependencies );
}
}
headerFile->Printf( "\r\n#endif // __GENERATED_SYSCALLS_H__\r\n" );
fileSystem->CloseFile( headerFile );
idFile* cppFile = fileSystem->OpenFileWrite( g_fixedCppFileName[ CS_FFC_SYSCALLS ], "fs_devpath" );
cppFile->Printf( "#include \"Precompiled.h\"\r\n" );
cppFile->Printf( "#pragma hdrstop\r\n\r\n" );
cppFile->Printf( "#include \"CompiledScript_Types.h\"\r\n" );
cppFile->Printf( "#include \"CompiledScript_Event.h\"\r\n" );
if ( dependencies.Num() > 0 ) {
cppFile->Printf( "// dependencies\r\n" );
for ( int i = 0; i < dependencies.Num(); i++ ) {
cppFile->Printf( "class %s;\r\n", BuildClassName( dependencies[ i ] ) );
}
cppFile->Printf( "\r\n" );
}
for ( int i = 0; i < sysCalls.Num(); i++ ) {
callDef_t* t = sysCalls[ i ];
cppFile->Printf( "%s SysCall%d( const sdCompiledScript_Event& _event", BuildFieldName( t->returnType ), i );
if ( t->parms.Num() > 0 ) {
cppFile->Printf( ", " );
for ( int j = 0; j < t->parms.Num(); j++ ) {
cppFile->Printf( "const %s& parm%d", BuildFieldName( t->parms[ j ] ), j );
if ( j != t->parms.Num() - 1 ) {
cppFile->Printf( ", " );
}
}
}
cppFile->Printf( " ) {\r\n" );
tabCount++;
if ( t->parms.Num() > 0 ) {
PrintTabs( cppFile );
cppFile->Printf( "UINT_PTR data[ %d ];\r\n", t->parms.Num() );
for ( int j = 0; j < t->parms.Num(); j++ ) {
const char* eventDataTypeName = NULL;
switch ( t->event->GetArgFormat()[ j ] ) {
case D_EVENT_VECTOR:
eventDataTypeName = "Vector";
break;
case D_EVENT_STRING:
eventDataTypeName = "String";
break;
case D_EVENT_WSTRING:
eventDataTypeName = "WString";
break;
case D_EVENT_ENTITY:
case D_EVENT_ENTITY_NULL:
eventDataTypeName = "Entity";
break;
case D_EVENT_OBJECT:
eventDataTypeName = "Object";
break;
case D_EVENT_BOOLEAN:
eventDataTypeName = "Boolean";
break;
case D_EVENT_FLOAT:
eventDataTypeName = "Float";
break;
case D_EVENT_INTEGER:
eventDataTypeName = "Integer";
break;
case D_EVENT_HANDLE:
eventDataTypeName = "Handle";
break;
default:
assert( false );
eventDataTypeName = "Unknown";
break;
}
if ( t->event->GetArgFormat()[ j ] == D_EVENT_ENTITY ) {
PrintTabs( cppFile );
cppFile->Printf( "if ( !parm%d.To%sData( data[ %d ] ) ) {\r\n", j, eventDataTypeName, j );
tabCount++;
PrintTabs( cppFile );
cppFile->Printf( "// TODO: Print warning\r\n" );
PrintTabs( cppFile );
if ( t->returnType->Type() != ev_void ) {
cppFile->Printf( "return %s();\r\n", BuildFieldName( t->returnType ) );
} else {
cppFile->Printf( "return;\r\n" );
}
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "}\r\n" );
} else {
PrintTabs( cppFile );
cppFile->Printf( "parm%d.To%sData( data[ %d ] );\r\n", j, eventDataTypeName, j );
}
}
}
PrintTabs( cppFile );
cppFile->Printf( "compilerInterface->SysCall( _event.GetEvent(), %s );\r\n", t->parms.Num() > 0 ? "data" : "NULL" );
const char* typeName;
switch ( t->event->GetReturnType() ) {
case D_EVENT_VECTOR:
typeName = "Vector";
break;
case D_EVENT_STRING:
typeName = "String";
break;
case D_EVENT_WSTRING:
typeName = "WString";
break;
case D_EVENT_ENTITY:
case D_EVENT_ENTITY_NULL:
case D_EVENT_OBJECT:
typeName = "Object";
break;
case D_EVENT_BOOLEAN:
typeName = "Boolean";
break;
case D_EVENT_HANDLE:
typeName = "Integer";
break;
case D_EVENT_INTEGER: // integers get returned as floats
case D_EVENT_FLOAT:
typeName = "Float";
break;
case D_EVENT_VOID:
typeName = NULL;
break;
default:
assert( false );
typeName = "Unknown";
break;
}
if ( typeName != NULL ) {
PrintTabs( cppFile );
cppFile->Printf( "return compilerInterface->GetReturned%s();\r\n", typeName );
}
tabCount--;
cppFile->Printf( "}\r\n\r\n" );
}
fileSystem->CloseFile( cppFile );
}
void sdScriptExporter::WriteEventCalls( void ) {
idList< const idTypeDef* > dependencies;
idFile* headerFile = fileSystem->OpenFileWrite( g_fixedHFileName[ CS_FFH_EVENTCALLS ], "fs_devpath" );
headerFile->Printf( "#ifndef __GENERATED_EVENTCALLS_H__\r\n" );
headerFile->Printf( "#define __GENERATED_EVENTCALLS_H__\r\n\r\n" );
for ( int i = 0; i < eventCalls.Num(); i++ ) {
callDef_t* t = eventCalls[ i ];
headerFile->Printf( "%s EventCall%d( const sdCompiledScript_Event& _event, %s* _obj", BuildFieldName( t->returnType ), i, BASE_COMPILED_SCRIPT_CLASS_ALLOCATE );
if ( t->parms.Num() > 0 ) {
headerFile->Printf( ", " );
for ( int j = 0; j < t->parms.Num(); j++ ) {
headerFile->Printf( "const %s& parm%d", BuildFieldName( t->parms[ j ] ), j );
if ( j != t->parms.Num() - 1 ) {
headerFile->Printf( ", " );
}
}
}
headerFile->Printf( " );\r\n" );
AddDependency( t->returnType, dependencies );
for ( int j = 0; j < t->parms.Num(); j++ ) {
AddDependency( t->parms[ j ], dependencies );
}
}
headerFile->Printf( "\r\n#endif // __GENERATED_EVENTCALLS_H__\r\n" );
fileSystem->CloseFile( headerFile );
idFile* cppFile = fileSystem->OpenFileWrite( g_fixedCppFileName[ CS_FFC_EVENTCALLS ], "fs_devpath" );
cppFile->Printf( "#include \"Precompiled.h\"\r\n" );
cppFile->Printf( "#pragma hdrstop\r\n\r\n" );
cppFile->Printf( "#include \"CompiledScript_Types.h\"\r\n" );
cppFile->Printf( "#include \"CompiledScript_Event.h\"\r\n" );
if ( dependencies.Num() > 0 ) {
cppFile->Printf( "// dependencies\r\n" );
for ( int i = 0; i < dependencies.Num(); i++ ) {
cppFile->Printf( "class %s;\r\n", BuildClassName( dependencies[ i ] ) );
}
cppFile->Printf( "\r\n" );
}
for ( int i = 0; i < eventCalls.Num(); i++ ) {
callDef_t* t = eventCalls[ i ];
cppFile->Printf( "%s EventCall%d( const sdCompiledScript_Event& _event, %s* _obj", BuildFieldName( t->returnType ), i, BASE_COMPILED_SCRIPT_CLASS_ALLOCATE );
if ( t->parms.Num() > 0 ) {
cppFile->Printf( ", " );
for ( int j = 0; j < t->parms.Num(); j++ ) {
cppFile->Printf( "const %s& parm%d", BuildFieldName( t->parms[ j ] ), j );
if ( j != t->parms.Num() - 1 ) {
cppFile->Printf( ", " );
}
}
}
cppFile->Printf( " ) {\r\n" );
tabCount++;
if ( t->parms.Num() > 0 ) {
PrintTabs( cppFile );
cppFile->Printf( "UINT_PTR data[ %d ];\r\n", t->parms.Num() );
for ( int j = 0; j < t->parms.Num(); j++ ) {
const char* eventDataTypeName = NULL;
switch ( t->event->GetArgFormat()[ j ] ) {
case D_EVENT_VECTOR:
eventDataTypeName = "Vector";
break;
case D_EVENT_STRING:
eventDataTypeName = "String";
break;
case D_EVENT_WSTRING:
eventDataTypeName = "WString";
break;
case D_EVENT_ENTITY:
case D_EVENT_ENTITY_NULL:
eventDataTypeName = "Entity";
break;
case D_EVENT_OBJECT:
eventDataTypeName = "Object";
break;
case D_EVENT_BOOLEAN:
eventDataTypeName = "Boolean";
break;
case D_EVENT_FLOAT:
eventDataTypeName = "Float";
break;
case D_EVENT_INTEGER:
eventDataTypeName = "Integer";
break;
case D_EVENT_HANDLE:
eventDataTypeName = "Handle";
break;
default:
assert( false );
eventDataTypeName = "Unknown";
break;
}
if ( t->event->GetArgFormat()[ j ] == D_EVENT_ENTITY ) {
PrintTabs( cppFile );
cppFile->Printf( "if ( !parm%d.To%sData( data[ %d ] ) ) {\r\n", j, eventDataTypeName, j );
tabCount++;
PrintTabs( cppFile );
cppFile->Printf( "// TODO: Print warning\r\n" );
PrintTabs( cppFile );
if ( t->returnType->Type() != ev_void ) {
cppFile->Printf( "return %s();\r\n", BuildFieldName( t->returnType ) );
} else {
cppFile->Printf( "return;\r\n" );
}
tabCount--;
PrintTabs( cppFile );
cppFile->Printf( "}\r\n" );
} else {
PrintTabs( cppFile );
cppFile->Printf( "parm%d.To%sData( data[ %d ] );\r\n", j, eventDataTypeName, j );
}
}
}
PrintTabs( cppFile );
cppFile->Printf( "compilerInterface->EventCall( _event.GetEvent(), _obj, %s );\r\n", t->parms.Num() > 0 ? "data" : "NULL" );
const char* typeName;
switch ( t->event->GetReturnType() ) {
case D_EVENT_VECTOR:
typeName = "Vector";
break;
case D_EVENT_STRING:
typeName = "String";
break;
case D_EVENT_WSTRING:
typeName = "WString";
break;
case D_EVENT_ENTITY:
case D_EVENT_ENTITY_NULL:
case D_EVENT_OBJECT:
typeName = "Object";
break;
case D_EVENT_BOOLEAN:
typeName = "Boolean";
break;
case D_EVENT_HANDLE:
typeName = "Integer";
break;
case D_EVENT_INTEGER: // integers get returned as floats
case D_EVENT_FLOAT:
typeName = "Float";
break;
case D_EVENT_VOID:
typeName = NULL;
break;
default:
assert( false );
typeName = "Unknown";
break;
}
if ( typeName != NULL ) {
PrintTabs( cppFile );
cppFile->Printf( "return compilerInterface->GetReturned%s();\r\n", typeName );
}
tabCount--;
cppFile->Printf( "}\r\n\r\n" );
}
fileSystem->CloseFile( cppFile );
}
void sdScriptExporter::WriteClassFunctionWrappers( void ) {
idList< const idTypeDef* > dependencies;
idFile* headerFile = fileSystem->OpenFileWrite( g_fixedHFileName[ CS_FFH_FUNCTIONWRAPPERS ], "fs_devpath" );
headerFile->Printf( "#ifndef __GENERATED_CLASSFUNCTIONWRAPPERS_H__\r\n" );
headerFile->Printf( "#define __GENERATED_CLASSFUNCTIONWRAPPERS_H__\r\n\r\n" );
for ( int i = 0; i < externalClassCalls.Num(); i++ ) {
callDef_t* t = externalClassCalls[ i ];
headerFile->Printf( "void ClassFunctionWrapper%d( %s* obj, classFunctionCallback_t callback, const byte* data );\r\n", i, BASE_COMPILED_SCRIPT_CLASS_ALLOCATE );
AddDependency( t->returnType, dependencies );
for ( int j = 0; j < t->parms.Num(); j++ ) {
AddDependency( t->parms[ j ], dependencies );
}
}
headerFile->Printf( "\r\n#endif // __GENERATED_CLASSFUNCTIONWRAPPERS_H__\r\n" );
fileSystem->CloseFile( headerFile );
idFile* cppFile = fileSystem->OpenFileWrite( g_fixedCppFileName[ CS_FFC_FUNCTIONWRAPPERS ], "fs_devpath" );
cppFile->Printf( "#include \"Precompiled.h\"\r\n" );
cppFile->Printf( "#pragma hdrstop\r\n\r\n" );
cppFile->Printf( "#include \"CompiledScript_Types.h\"\r\n" );
if ( dependencies.Num() > 0 ) {
cppFile->Printf( "// dependencies\r\n" );
for ( int i = 0; i < dependencies.Num(); i++ ) {
cppFile->Printf( "#include \"%s\"\r\n", BuildClassHeaderName( dependencies[ i ], false ) );
}
cppFile->Printf( "\r\n" );
}
for ( int i = 0; i < externalClassCalls.Num(); i++ ) {
callDef_t* t = externalClassCalls[ i ];
cppFile->Printf( "void ClassFunctionWrapper%d( %s* obj, classFunctionCallback_t callback, const byte* data ) {\r\n", i, BASE_COMPILED_SCRIPT_CLASS_ALLOCATE );
tabCount++;
PrintTabs( cppFile );
cppFile->Printf( "typedef %s ( %s::*internalCallback_t )(", BuildFieldName( t->returnType ), BASE_COMPILED_SCRIPT_CLASS_ALLOCATE );
if ( t->parms.Num() > 0 ) {
cppFile->Printf( " " );
for ( int j = 0; j < t->parms.Num(); j++ ) {
cppFile->Printf( "%s parm%d", BuildFieldName( t->parms[ j ] ), j );
if ( j != t->parms.Num() - 1 ) {
cppFile->Printf( ", " );
}
}
cppFile->Printf( " " );
}
cppFile->Printf( ");\r\n" );
if ( t->parms.Num() > 0 ) {
PrintTabs( cppFile );
cppFile->Printf( "const byte* p = data;\r\n" );
for ( int j = 0; j < t->parms.Num(); j++ ) {
PrintTabs( cppFile );
cppFile->Printf( "%s parm%d;\r\n", BuildFieldName( t->parms[ j ] ), j );
PrintTabs( cppFile );
cppFile->Printf( "p = parm%d.FromData( p );\r\n", j );
}
}
PrintTabs( cppFile );
cppFile->Printf( "internalCallback_t internalCallback = ( internalCallback_t )callback;\r\n" );
PrintTabs( cppFile );
if ( t->returnType->Type() != ev_void ) {
cppFile->Printf( "compilerInterface->Return" );
switch ( t->returnType->Type() ) {
case ev_float:
cppFile->Printf( "Float" );
break;
case ev_boolean:
cppFile->Printf( "Boolean" );
break;
case ev_vector:
cppFile->Printf( "Vector" );
break;
case ev_object:
cppFile->Printf( "Object" );
break;
case ev_string:
cppFile->Printf( "String" );
break;
case ev_wstring:
cppFile->Printf( "WString" );
break;
default:
assert( false );
break;
}
cppFile->Printf( "( " );
}
cppFile->Printf( "( *obj.*internalCallback )(" );
if ( t->parms.Num() > 0 ) {
cppFile->Printf( " " );
for ( int j = 0; j < t->parms.Num(); j++ ) {
cppFile->Printf( "parm%d", j );
if ( j != t->parms.Num() - 1 ) {
cppFile->Printf( ", " );
}
}
cppFile->Printf( " " );
}
if ( t->returnType->Type() != ev_void ) {
cppFile->Printf( " ) " );
}
cppFile->Printf( ");\r\n" );
tabCount--;
cppFile->Printf( "}\r\n\r\n" );
}
fileSystem->CloseFile( cppFile );
}
void sdScriptExporter::WriteFunctionWrappers( idFile* cppFile ) {
for ( int i = 0; i < externalFunctionCalls.Num(); i++ ) {
callDef_t* t = externalFunctionCalls[ i ];
cppFile->Printf( "void GlobalFunctionWrapper%d( functionCallback_t callback, const byte* data ) {\r\n", i );
tabCount++;
PrintTabs( cppFile );
cppFile->Printf( "typedef %s ( *internalCallback_t )(", BuildFieldName( t->returnType ) );
if ( t->parms.Num() > 0 ) {
cppFile->Printf( " " );
for ( int j = 0; j < t->parms.Num(); j++ ) {
cppFile->Printf( "%s parm%d", BuildFieldName( t->parms[ j ] ), j );
if ( j != t->parms.Num() - 1 ) {
cppFile->Printf( ", " );
}
}
cppFile->Printf( " " );
}
cppFile->Printf( ");\r\n" );
if ( t->parms.Num() > 0 ) {
PrintTabs( cppFile );
cppFile->Printf( "const byte* p = data;\r\n" );
for ( int j = 0; j < t->parms.Num(); j++ ) {
PrintTabs( cppFile );
cppFile->Printf( "%s parm%d;\r\n", BuildFieldName( t->parms[ j ] ), j );
PrintTabs( cppFile );
cppFile->Printf( "p = parm%d.FromData( p );\r\n", j );
}
}
PrintTabs( cppFile );
cppFile->Printf( "internalCallback_t internalCallback = ( internalCallback_t )callback;\r\n" );
PrintTabs( cppFile );
if ( t->returnType->Type() != ev_void ) {
cppFile->Printf( "compilerInterface->Return" );
switch ( t->returnType->Type() ) {
case ev_float:
cppFile->Printf( "Float" );
break;
case ev_boolean:
cppFile->Printf( "Boolean" );
break;
case ev_vector:
cppFile->Printf( "Vector" );
break;
case ev_object:
cppFile->Printf( "Object" );
break;
case ev_string:
cppFile->Printf( "String" );
break;
case ev_wstring:
cppFile->Printf( "WString" );
break;
default:
assert( false );
break;
}
cppFile->Printf( "( " );
}
cppFile->Printf( "( *internalCallback )(" );
if ( t->parms.Num() > 0 ) {
cppFile->Printf( " " );
for ( int j = 0; j < t->parms.Num(); j++ ) {
cppFile->Printf( "parm%d", j );
if ( j != t->parms.Num() - 1 ) {
cppFile->Printf( ", " );
}
}
cppFile->Printf( " " );
}
if ( t->returnType->Type() != ev_void ) {
cppFile->Printf( " ) " );
}
cppFile->Printf( ");\r\n" );
tabCount--;
cppFile->Printf( "}\r\n\r\n" );
}
}
void sdScriptExporter::WriteVirtualFunctions( void ) {
idFile* headerFile;
headerFile = fileSystem->OpenFileWrite( g_fixedHFileName[ CS_FFH_VIRTUALFUNCTIONS ], "fs_devpath" );
idList< const idTypeDef* > dependencies;
for ( int i = 0; i < virtualFunctions.Num(); i++ ) {
functionDef_t funcDef;
funcDef.function = virtualFunctions[ i ]->def->value.functionPtr;
funcDef.isVirtual = true;
AddDependency( funcDef.function, dependencies, false );
WriteFunctionStub( headerFile, funcDef, NULL, 0 );
if ( funcDef.function->type->ReturnType()->Type() != ev_void ) {
headerFile->Printf( "{ return %s(); }\r\n", BuildFieldName( funcDef.function->type->ReturnType() ) );
} else {
headerFile->Printf( "{ ; }\r\n" );
}
}
fileSystem->CloseFile( headerFile );
headerFile = fileSystem->OpenFileWrite( g_fixedHFileName[ CS_FFH_VIRTUALFUNCTIONDEPENDANCIES ], "fs_devpath" );
if ( dependencies.Num() > 0 ) {
headerFile->Printf( "// dependencies\r\n" );
for ( int i = 0; i < dependencies.Num(); i++ ) {
headerFile->Printf( "class %s;\r\n", BuildClassName( dependencies[ i ] ) );
}
headerFile->Printf( "\r\n" );
}
fileSystem->CloseFile( headerFile );
}
void sdScriptExporter::WriteNamespaceClasses( const namespaceDef_t* ns ) {
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
WriteNamespaceClasses( ns->namespaces[ i ] );
}
for ( int i = 1; i < ns->classes.Num(); i++ ) {
WriteClass( ns, *ns->classes[ i ] );
}
}
void sdScriptExporter::ClearNamespace( namespaceDef_t* ns ) {
ns->classes.DeleteContents( true );
ns->globalVars.Clear();
for ( int i = 0; i < ns->namespaces.Num(); i++ ) {
ClearNamespace( ns->namespaces[ i ] );
}
ns->namespaces.DeleteContents( true );
ns->parentNamespace = NULL;
ns->name = "";
}
void sdScriptExporter::Clear( bool finished ) {
ClearNamespace( &globalNameSpace );
events.Clear();
currentNameSpace = &globalNameSpace;
virtualFunctions.Clear();
if ( !finished ) {
RegisterClass( NULL, NULL );
}
externalClassCalls.DeleteContents( true );
externalFunctionCalls.DeleteContents( true );
sysCalls.DeleteContents( true );
eventCalls.DeleteContents( true );
generatedCppFiles.Clear();
generatedHFiles.Clear();
constants.Clear();
}
void sdScriptExporter::RegisterVirtualFunction( idTypeDef* type ) {
virtualFunctions.Alloc() = type;
}
void sdScriptExporter::RegisterClass( idTypeDef* type, idTypeDef* superType ) {
objectDef_t* def = new objectDef_t;
currentNameSpace->classes.Alloc() = def;
def->type = type;
if ( superType != NULL && superType != &type_object ) {
objectDef_t* superClass = FindClass( currentNameSpace, superType );
assert( superClass != NULL );
def->superType = superClass;
def->baseOffset = superClass->baseOffset;
for ( int i = 0; i < superClass->fields.Num(); i++ ) {
def->baseOffset += FieldSize( superClass->fields[ i ]->TypeDef()->FieldType() );
}
} else {
def->superType = NULL;
def->baseOffset = 0;
}
}
sdScriptExporter::stackVar_t* sdScriptExporter::FindGlobal( const namespaceDef_t* ns, const idVarDef* var ) {
int varNum = GetVarDefNum( var );
assert( varNum != -1 );
for ( int i = 0; i < ns->globalVars.Num(); i++ ) {
if ( ns->globalVars[ i ]->offset != varNum ) {
continue;
}
if ( ns->globalVars[ i ]->type->Type() == ev_vector ) {
if ( var->Type() == ev_float ) {
assert( false );
}
}
return ns->globalVars[ i ];
}
if ( ns->parentNamespace != NULL ) {
return FindGlobal( ns->parentNamespace, var );
}
return NULL;
}
sdScriptExporter::objectDef_t* sdScriptExporter::FindClass( const namespaceDef_t* ns, const idTypeDef* type ) {
for ( int i = 0; i < ns->classes.Num(); i++ ) {
if ( ns->classes[ i ]->type == type ) {
return ns->classes[ i ];
}
}
if ( ns->parentNamespace != NULL ) {
return FindClass( ns->parentNamespace, type );
}
gameLocal.Error( "sdScriptExporter::FindClass Unknown Type '%s'", type->Name() );
return NULL;
}
void sdScriptExporter::RegisterClassFunction( idTypeDef* type, const function_t* function ) {
objectDef_t* o = FindClass( currentNameSpace, type );
functionDef_t& f = o->functions.Alloc();
f.function = function;
f.isVirtual = false;
bool isSpecial = false;
const char* specialFuncs[] = {
"init",
"preinit",
"destroy",
"syncFields",
NULL
};
bool makeVirtual = false;
if ( function->virtualIndex != -1 ) {
makeVirtual = true;
}
if ( !makeVirtual ) {
for ( int i = 0; specialFuncs[ i ] != NULL; i++ ) {
if ( idStr::Cmp( specialFuncs[ i ], function->type->Name() ) == 0 ) {
isSpecial = true;
break;
}
}
if ( !isSpecial ) {
for ( objectDef_t* p = o->superType; p != NULL; p = p->superType ) {
for ( int i = 0; i < p->functions.Num(); i++ ) {
if ( idStr::Cmp( p->functions[ i ].function->type->Name(), function->type->Name() ) != 0 ) {
continue;
}
makeVirtual = true;
goto end;
}
}
}
}
end:
if ( makeVirtual ) {
f.isVirtual = true;
for ( objectDef_t* p = o->superType; p != NULL; p = p->superType ) {
for ( int i = 0; i < p->functions.Num(); i++ ) {
if ( idStr::Cmp( p->functions[ i ].function->type->Name(), function->type->Name() ) != 0 ) {
continue;
}
p->functions[ i ].isVirtual = true;
break;
}
}
}
}
void sdScriptExporter::RegisterClassFunctionVariable( idTypeDef* type, const function_t* function, const idVarDef* var ) {
objectDef_t* o = FindClass( currentNameSpace, type );
for ( int i = 0; i < o->functions.Num(); i++ ) {
if ( o->functions[ i ].function != function ) {
continue;
}
o->functions[ i ].variables.Alloc() = var;
break;
}
}
void sdScriptExporter::RegisterClassField( idTypeDef* type, idVarDef* field ) {
objectDef_t* o = FindClass( currentNameSpace, type );
o->fields.Alloc() = field;
}
sdFunctionCompileState::sdFunctionCompileState( const sdScriptExporter::functionDef_t* _func, const sdScriptExporter::namespaceDef_t* _nameSpace, idFile* _output, int initialTabCount, idProgram* _program ) {
fileOutput = _output;
func = _func;
tabCount = initialTabCount;
returnVar = NULL;
skipNextStatement = false;
nameSpace = _nameSpace;
program = _program;
output = fileSystem->OpenMemoryFile( "sdFunctionCompileState output" );
variables = fileSystem->OpenMemoryFile( "sdFunctionCompileState variables" );
}
sdFunctionCompileState::~sdFunctionCompileState() {
stackVars.DeleteContents( true );
fileSystem->CloseFile( output );
fileSystem->CloseFile( variables );
}
void sdFunctionCompileState::Run( void ) {
isSpecial = false;
if ( idStr::Cmp( func->function->type->Name(), "destroy" ) == 0 ) {
isSpecial = true;
}
AllocBaseStackVars();
ScanForLabels();
ScanOpCodes();
fileOutput->Write( variables->GetDataPtr(), variables->Tell() );
fileOutput->Write( output->GetDataPtr(), output->Tell() );
}
void sdFunctionCompileState::ScanForLabels( void ) {
int lastStatement = func->function->firstStatement + func->function->numStatements;
for ( int i = func->function->firstStatement; i < lastStatement; i++ ) {
statement_t& s = program->GetStatement( i );
switch ( s.op ) {
case OP_IF:
case OP_IFNOT: {
assert( s.b->settings.initialized == idVarDef::initializedConstant && s.b->TypeDef()->Type() == ev_jumpoffset );
int address = i + s.b->value.jumpOffset;
labels.AddUnique( address );
break;
}
case OP_GOTO: {
assert( s.a->settings.initialized == idVarDef::initializedConstant && s.a->TypeDef()->Type() == ev_jumpoffset );
int address = i + s.a->value.jumpOffset;
labels.AddUnique( address );
break;
}
}
}
}
void sdFunctionCompileState::ScanOpCodes( void ) {
for ( int i = func->function->firstStatement; i < func->function->firstStatement + func->function->numStatements; i++ ) {
if ( skipNextStatement ) {
skipNextStatement = false;
continue;
}
ScanOpCode( i );
}
assert( compileStack.Num() == 0 );
}
bool sdFunctionCompileState::IsReturn( const idVarDef* var ) {
return var == program->returnDef || var == program->returnStringDef;
}
sdScriptExporter::stackVar_t* sdFunctionCompileState::FindStackVar( const idVarDef* var ) {
for ( int i = 0; i < stackVars.Num(); i++ ) {
if ( stackVars[ i ]->offset == var->value.stackOffset && stackVars[ i ]->type->Type() == var->Type() ) {
return stackVars[ i ];
}
}
return NULL;
}
void sdFunctionCompileState::AllocateSubVars( const sdScriptExporter::stackVar_t& var ) {
if ( var.type->Type() != ev_vector ) {
return;
}
sdScriptExporter::stackVar_t& newVar1 = *new sdScriptExporter::stackVar_t;
sdScriptExporter::stackVar_t& newVar2 = *new sdScriptExporter::stackVar_t;
sdScriptExporter::stackVar_t& newVar3 = *new sdScriptExporter::stackVar_t;
stackVars.Alloc() = &newVar1;
stackVars.Alloc() = &newVar2;
stackVars.Alloc() = &newVar3;
newVar1.type = &type_float;
newVar1.offset = var.offset + type_float.Size() * 0;
newVar1.name = var.name + ".GetX()";
newVar1.allocated = true;
newVar2.type = &type_float;
newVar2.offset = var.offset + type_float.Size() * 1;
newVar2.name = var.name + ".GetY()";
newVar2.allocated = true;
newVar3.type = &type_float;
newVar3.offset = var.offset + type_float.Size() * 2;
newVar3.name = var.name + ".GetZ()";
newVar3.allocated = true;
}
void sdFunctionCompileState::AllocBaseStackVars( void ) {
for ( int i = 0; i < func->variables.Num(); i++ ) {
const idVarDef* var = func->variables[ i ];
sdScriptExporter::stackVar_t& newVar = *new sdScriptExporter::stackVar_t;
newVar.type = var->TypeDef();
newVar.offset = var->value.stackOffset;
newVar.name = var->Name();
newVar.allocated = false;
stackVars.Alloc() = &newVar;
InitStackVar( newVar );
AllocateSubVars( newVar );
}
int base = func->function->def->scope->Type() == ev_namespace ? 0 : 1;
int localOffset = 0;
for ( int i = 0; i < func->function->type->NumParameters(); i++ ) {
idTypeDef* type = func->function->type->GetParmType( i );
sdScriptExporter::stackVar_t& newVar = *new sdScriptExporter::stackVar_t;
newVar.type = type;
newVar.offset = localOffset;
newVar.name = func->function->type->GetParmName( i );
newVar.allocated = true;
stackVars.Alloc() = &newVar;
AllocateSubVars( newVar );
localOffset += sdScriptExporter::FieldSize( type );
}
}
sdScriptExporter::stackVar_t& sdFunctionCompileState::AllocStackVar( const idVarDef* var ) {
sdScriptExporter::stackVar_t* s = FindStackVar( var );
if ( s != NULL ) {
return *s;
}
if ( idStr::Cmp( var->Name(), "<RESULT>" ) != 0 ) {
assert( false );
}
assert( var->TypeDef() != NULL );
sdScriptExporter::stackVar_t& newVar = *new sdScriptExporter::stackVar_t;
newVar.type = var->TypeDef();
newVar.offset = var->value.stackOffset;
newVar.name = va( "__stackVar%d", stackVars.Num() );
newVar.allocated = false;
stackVars.Alloc() = &newVar;
return newVar;
}
void sdFunctionCompileState::PrintField( idTypeDef* type, idVarDef* ptr ) {
const char* fieldName = program->scriptExporter.FindFieldName( nameSpace, type, ptr );
if ( fieldName == NULL ) {
output->Printf( "[unknown field]" );
return;
}
output->Printf( fieldName );
}
void sdFunctionCompileState::InitStackVar( sdScriptExporter::stackVar_t& var ) {
if ( var.allocated ) {
assert( false );
return;
}
variables->Printf( "\t%s %s;\r\n", program->scriptExporter.BuildFieldName( var.type, ev_error /* defaultType */ ), var.name.c_str() );
var.allocated = true;
}
void sdFunctionCompileState::CheckVariable( const idVarDef* var, etype_t defaultType ) {
if ( var->settings.initialized == var->initializedConstant || var->settings.initialized == var->initializedVariable ) {
return;
}
if ( var->settings.initialized == var->stackVariable ) {
if ( func->function->def->scope->Type() != ev_namespace ) {
if ( idStr::Cmp( var->Name(), "self" ) == 0 ) {
return;
}
}
sdScriptExporter::stackVar_t& stackVar = AllocStackVar( var );
if ( !stackVar.allocated ) {
InitStackVar( stackVar );
}
return;
}
}
void sdFunctionCompileState::GetVariableName( const idVarDef* var, etype_t expectedType, idStr& name ) {
if ( var->settings.initialized == var->initializedConstant ) {
idTypeDef* type = var->TypeDef();
int index = program->scriptExporter.AllocConstant( var );
if ( index == -1 ) {
name = "[unknown constant]";
assert( false );
} else {
name = program->scriptExporter.BuildConstantName( index );
}
return;
}
if ( var->settings.initialized == var->stackVariable ) {
if ( func->function->def->scope->Type() != ev_namespace ) {
if ( idStr::Cmp( var->Name(), "self" ) == 0 ) {
name = "this";
return;
}
}
sdScriptExporter::stackVar_t& stackVar = AllocStackVar( var );
// assert( stackVar.allocated );
name = stackVar.name.c_str();
return;
}
sdScriptExporter::stackVar_t* stackVar = program->scriptExporter.FindGlobal( nameSpace, var );
assert( stackVar != NULL );
name = program->scriptExporter.BuildGlobalName( *stackVar );
}
void sdFunctionCompileState::PrintVariable( const idVarDef* var, etype_t expectedType ) {
idStr name;
GetVariableName( var, expectedType, name );
output->Printf( "%s", name.c_str() );
}
void sdFunctionCompileState::PrintTabs( void ) {
for ( int t = tabCount; t > 0; t-- ) {
output->Printf( "\t" );
}
}
bool sdFunctionCompileState::LookAheadStore( int statement ) {
int lookahead = statement + 1;
if ( lookahead >= program->NumStatements() ) {
return false;
}
statement_t& s = program->GetStatement( lookahead );
switch ( s.op ) {
case OP_STORE_F:
case OP_STORE_V:
case OP_STORE_S:
case OP_STORE_W:
case OP_STORE_BOOL:
case OP_STORE_OBJ:
case OP_STORE_FTOS:
case OP_STORE_BTOS:
case OP_STORE_VTOS:
case OP_STORE_FTOBOOL:
case OP_STORE_BOOLTOF:
case OP_STOREP_F:
case OP_STOREP_V:
case OP_STOREP_S:
case OP_STOREP_W:
case OP_STOREP_FLD:
case OP_STOREP_BOOL:
case OP_STOREP_OBJ:
case OP_STOREP_FTOS:
case OP_STOREP_BTOS:
case OP_STOREP_VTOS:
case OP_STOREP_FTOBOOL:
case OP_STOREP_BOOLTOF: {
if ( IsReturn( s.a ) ) {
ScanOpCode( lookahead );
return true;
}
return false;
}
default:
return false;
}
}
#define TYPE_OF( TYPE ) idCompiler::opcodes[ s.op ].TYPE->Type()
void sdFunctionCompileState::ScanOpCode( int statement ) {
// output->Printf( "//" );
// program->DisassembleStatement( output, statement );
int labelIndex = labels.FindIndex( statement );
if ( labelIndex != -1 ) {
output->Printf( "label%d:\r\n", labelIndex );
}
statement_t& s = program->GetStatement( statement );
switch ( s.op ) {
case OP_PUSH_F:
case OP_PUSH_V:
case OP_PUSH_S:
case OP_PUSH_W:
case OP_PUSH_OBJ:
case OP_PUSH_FTOS:
case OP_PUSH_FTOW:
case OP_PUSH_BTOF:
case OP_PUSH_FTOB:
case OP_PUSH_VTOS:
case OP_PUSH_BTOS: {
compileStack.Alloc() = s.a;
return;
}
case OP_EQ_B:
case OP_EQ_F:
case OP_EQ_V:
case OP_EQ_S:
case OP_EQ_W:
case OP_EQ_O: {
CheckVariable( s.c, TYPE_OF( type_c ) );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " == " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_ADDRESS: {
CheckVariable( s.a );
idStr varName;
GetVariableName( s.a, ev_object, varName );
varName += va( "->%s", program->scriptExporter.FindFieldName( nameSpace, s.a->TypeDef(), s.b ) );
sdScriptExporter::stackVar_t* stackVar = FindStackVar( s.c );
if ( stackVar == NULL ) {
stackVar = new sdScriptExporter::stackVar_t;
stackVars.Alloc() = stackVar;
}
stackVar->allocated = true;
stackVar->name = varName;
stackVar->offset = s.c->value.stackOffset;
stackVar->type = s.c->TypeDef();
return;
}
case OP_UAND_F: {
CheckVariable( s.b, idCompiler::opcodes[ s.op ].type_b->Type() );
PrintTabs();
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( " &= " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ";\r\n" );
return;
}
case OP_UOR_F: {
CheckVariable( s.b, idCompiler::opcodes[ s.op ].type_b->Type() );
PrintTabs();
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( " |= " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ";\r\n" );
return;
}
case OP_BITOR: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " | " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_BITAND: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " & " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_OR:
case OP_OR_BOOLBOOL:
case OP_OR_FBOOL:
case OP_OR_BOOLF: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " || " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_AND:
case OP_AND_BOOLBOOL:
case OP_AND_BOOLF:
case OP_AND_FBOOL: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " && " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_NE_B:
case OP_NE_F:
case OP_NE_V:
case OP_NE_S:
case OP_NE_W:
case OP_NE_O: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " != " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_NEG_V:
case OP_NEG_F: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = -" );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ";\r\n" );
return;
}
case OP_INT_F: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ".ToInt();\r\n" );
return;
}
case OP_DIV_F: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " / " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_MUL_V:
case OP_MUL_VF:
case OP_MUL_FV:
case OP_MUL_F: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " * " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_ADD_F:
case OP_ADD_V:
case OP_ADD_S:
case OP_ADD_FS:
case OP_ADD_SF:
case OP_ADD_VS:
case OP_ADD_SV: {
CheckVariable( s.a, idCompiler::opcodes[ s.op ].type_a->Type() );
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " + " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_SUB_F:
case OP_SUB_V: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " - " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_LE: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " <= " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_GE: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " >= " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_GT: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " > " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_MOD_F: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " %% " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_USUB_V:
case OP_USUB_F: {
PrintTabs();
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( " -= " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ";\r\n" );
return;
}
case OP_UMUL_F:
case OP_UMUL_V: {
PrintTabs();
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( " *= " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ";\r\n" );
return;
}
case OP_UDIV_F:
case OP_UDIV_V: {
PrintTabs();
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( " /= " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ";\r\n" );
return;
}
case OP_UADD_F:
case OP_UADD_V: {
PrintTabs();
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( " += " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ";\r\n" );
return;
}
case OP_UINCP_F: {
CheckVariable( s.a );
PrintTabs();
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( "->%s++;\r\n", program->scriptExporter.FindFieldName( nameSpace, s.a->TypeDef(), s.b ) );
return;
}
case OP_UDECP_F: {
CheckVariable( s.a );
PrintTabs();
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( "->%s--;\r\n", program->scriptExporter.FindFieldName( nameSpace, s.a->TypeDef(), s.b ) );
return;
}
case OP_UINC_F: {
PrintTabs();
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( "++;\r\n" );
return;
}
case OP_UDEC_F: {
PrintTabs();
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( "--;\r\n" );
return;
}
case OP_LT: {
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " < " );
PrintVariable( s.b, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_NOT_BOOL:
case OP_NOT_F:
case OP_NOT_V:
case OP_NOT_S:
case OP_NOT_OBJ: {
CheckVariable( s.a );
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = !" );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( ";\r\n" );
return;
}
case OP_IFNOT: {
PrintTabs();
output->Printf( "if ( !" );
PrintVariable( s.a, ev_error );
output->Printf( " ) {\r\n" );
tabCount++;
PrintTabs();
output->Printf( "goto " );
tabCount--;
int index = labels.FindIndex( statement + s.b->value.jumpOffset );
assert( index != -1 );
output->Printf( "label%d;\r\n", index );
PrintTabs();
output->Printf( "}\r\n", index );
return;
}
case OP_IF: {
PrintTabs();
output->Printf( "if ( " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " ) {\r\n" );
tabCount++;
PrintTabs();
output->Printf( "goto " );
tabCount--;
int index = labels.FindIndex( statement + s.b->value.jumpOffset );
assert( index != -1 );
output->Printf( "label%d;\r\n", index );
PrintTabs();
output->Printf( "}\r\n", index );
return;
}
case OP_GOTO: {
int address = statement + s.a->value.jumpOffset;
PrintTabs();
output->Printf( "goto " );
int index = labels.FindIndex( address );
assert( index != -1 );
output->Printf( "label%d;\r\n", index );
return;
}
case OP_STORE_F:
case OP_STORE_V:
case OP_STORE_S:
case OP_STORE_W:
case OP_STORE_BOOL:
case OP_STORE_FTOS:
case OP_STORE_BTOS:
case OP_STORE_VTOS:
case OP_STORE_FTOBOOL:
case OP_STORE_BOOLTOF:
case OP_STOREP_F:
case OP_STOREP_V:
case OP_STOREP_S:
case OP_STOREP_W:
case OP_STOREP_FLD:
case OP_STOREP_BOOL:
case OP_STOREP_FTOS:
case OP_STOREP_BTOS:
case OP_STOREP_VTOS:
case OP_STOREP_FTOBOOL:
case OP_STOREP_BOOLTOF: {
if ( IsReturn( s.b ) ) {
returnVar = s.a;
return;
}
CheckVariable( s.b, TYPE_OF( type_c ) );
PrintTabs();
PrintVariable( s.b, TYPE_OF( type_c ) );
output->Printf( " = " );
if ( IsReturn( s.a ) ) {
return;
}
PrintVariable( s.a, TYPE_OF( type_b ) );
output->Printf( ";\r\n" );
return;
}
case OP_STORE_OBJ:
case OP_STOREP_OBJ: {
if ( IsReturn( s.b ) ) {
returnVar = s.a;
return;
}
CheckVariable( s.b, TYPE_OF( type_c ) );
PrintTabs();
PrintVariable( s.b, TYPE_OF( type_c ) );
output->Printf( " = " );
if ( IsReturn( s.a ) ) {
return;
}
PrintVariable( s.a, TYPE_OF( type_b ) );
idTypeDef* setType = s.b->TypeDef();
idTypeDef* getType = s.a->TypeDef();
if ( setType != getType && setType->Inherits( getType ) ) {
output->Printf( "->Cast< %s >()", program->scriptExporter.BuildClassName( setType ) );
}
output->Printf( ";\r\n" );
return;
}
case OP_EVENTCALL: {
const function_t* f = s.a->value.functionPtr;
int parms = f->type->NumParameters() + 1; // doesn't include self
assert( compileStack.Num() >= parms );
skipNextStatement = LookAheadStore( statement );
int base = compileStack.Num() - parms;
if ( !skipNextStatement ) {
PrintTabs();
}
int index = program->scriptExporter.RegisterEventCall( f );
output->Printf( "EventCall%d", index );
output->Printf( "( %s, ", program->scriptExporter.BuildEventName( f->type->Name() ) );
for ( int i = 0; i < parms; i++ ) {
etype_t expectedType;
if ( i > 0 ) {
expectedType = f->type->GetParmType( i - 1 )->Type();
} else {
expectedType = ev_error;
}
PrintVariable( compileStack[ base + i ], expectedType );
if ( i != parms - 1 ) {
output->Printf( ", " );
}
}
output->Printf( " );\r\n" );
compileStack.SetNum( compileStack.Num() - parms );
return;
}
case OP_CALL: {
const function_t* f = s.a->value.functionPtr;
int parms = f->type->NumParameters();
assert( compileStack.Num() >= parms );
skipNextStatement = LookAheadStore( statement );
int base = compileStack.Num() - parms;
if ( !skipNextStatement ) {
PrintTabs();
}
output->Printf( "%s(", program->scriptExporter.BuildGlobalFunctionName( f ) );
if ( parms > 0 ) {
output->Printf( " " );
for ( int i = 0; i < parms; i++ ) {
PrintVariable( compileStack[ base + i ], f->type->GetParmType( i )->Type() );
if ( i != parms - 1 ) {
output->Printf( ", " );
}
}
output->Printf( " " );
}
output->Printf( ");\r\n" );
compileStack.SetNum( compileStack.Num() - parms );
return;
}
case OP_VIRTUALEVENTCALL: {
const function_t* f = s.c->value.functionPtr;
int parms = f->type->NumParameters();
assert( compileStack.Num() >= parms );
skipNextStatement = LookAheadStore( statement );
int base = compileStack.Num() - ( parms + 1 );
if ( !skipNextStatement ) {
if ( g_compiledScriptSafety.GetBool() ) {
PrintTabs();
output->Printf( "if ( " );
PrintVariable( compileStack[ base ], ev_error );
output->Printf( " != NULL ) {\r\n" );
tabCount++;
}
PrintTabs();
} else {
if ( g_compiledScriptSafety.GetBool() ) {
PrintVariable( compileStack[ base ], ev_error );
output->Printf( " == NULL ? %s() : ", program->scriptExporter.BuildFieldName( f->type->ReturnType() ) );
}
}
PrintVariable( compileStack[ base ], ev_error );
output->Printf( "->%s(", f->type->Name() );
if ( parms > 0 ) {
output->Printf( " " );
for ( int i = 0; i < parms; i++ ) {
PrintVariable( compileStack[ base + i + 1 ], f->type->GetParmType( i )->Type() );
if ( i != parms - 1 ) {
output->Printf( ", " );
}
}
output->Printf( " " );
}
output->Printf( ");\r\n" );
if ( g_compiledScriptSafety.GetBool() ) {
if ( !skipNextStatement ) {
tabCount--;
PrintTabs();
output->Printf( "}\r\n" );
}
}
compileStack.SetNum( compileStack.Num() - ( parms + 1 ) );
return;
}
case OP_OBJECTCALL: {
const function_t* f = s.c->value.functionPtr;
int parms = f->type->NumParameters();
assert( compileStack.Num() >= parms );
skipNextStatement = LookAheadStore( statement );
int base = compileStack.Num() - parms;
if ( !skipNextStatement ) {
if ( g_compiledScriptSafety.GetBool() ) {
PrintTabs();
output->Printf( "if ( " );
PrintVariable( compileStack[ base ], ev_error );
output->Printf( " != NULL ) {\r\n" );
tabCount++;
}
PrintTabs();
} else {
if ( g_compiledScriptSafety.GetBool() ) {
PrintVariable( compileStack[ base ], ev_error );
output->Printf( " == NULL ? %s() : ", program->scriptExporter.BuildFieldName( f->type->ReturnType() ) );
}
}
PrintVariable( compileStack[ base ], f->type->GetParmType( 0 )->Type() );
output->Printf( "->%s(", f->type->Name() );
if ( parms > 1 ) {
output->Printf( " " );
for ( int i = 1; i < parms; i++ ) {
PrintVariable( compileStack[ base + i ], f->type->GetParmType( i )->Type() );
if ( i != parms - 1 ) {
output->Printf( ", " );
}
}
output->Printf( " " );
}
output->Printf( ");\r\n" );
if ( g_compiledScriptSafety.GetBool() ) {
if ( !skipNextStatement ) {
tabCount--;
PrintTabs();
output->Printf( "}\r\n" );
}
}
compileStack.SetNum( compileStack.Num() - parms );
return;
}
case OP_SYSCALL: {
const function_t* f = s.a->value.functionPtr;
if ( idStr::Cmp( f->GetName(), "wait" ) == 0 ) {
int base = compileStack.Num() - 1;
PrintTabs();
output->Printf( "compilerInterface->Wait( " );
PrintVariable( compileStack[ base ], f->type->GetParmType( 0 )->Type() );
output->Printf( " );\r\n" );
compileStack.SetNum( compileStack.Num() - 1 );
return;
}
if ( idStr::Cmp( f->GetName(), "waitFrame" ) == 0 ) {
PrintTabs();
output->Printf( "compilerInterface->WaitFrame();\r\n" );
return;
}
int parms = f->type->NumParameters();
assert( compileStack.Num() >= parms );
skipNextStatement = LookAheadStore( statement );
int base = compileStack.Num() - parms;
if ( !skipNextStatement ) {
PrintTabs();
}
int index = program->scriptExporter.RegisterSysCall( f );
output->Printf( "SysCall%d", index );
output->Printf( "( %s", program->scriptExporter.BuildEventName( f->type->Name() ) );
if ( parms > 0 ) {
output->Printf( ", " );
for ( int i = 0; i < parms; i++ ) {
PrintVariable( compileStack[ base + i ], f->type->GetParmType( i )->Type() );
if ( i != parms - 1 ) {
output->Printf( ", " );
}
}
}
output->Printf( " );\r\n" );
compileStack.SetNum( compileStack.Num() - parms );
return;
}
case OP_GUITHREAD:
case OP_THREAD: {
const function_t* f = s.a->value.functionPtr;
int parms = f->type->NumParameters();
assert( compileStack.Num() >= parms );
sdScriptExporter::objectDef_t* o = program->scriptExporter.FindClass( &program->scriptExporter.GetGlobalNamespace(), NULL );
int index = program->scriptExporter.FindThreadCall( *o, f, s.op == OP_GUITHREAD );
skipNextStatement = LookAheadStore( statement );
int base = compileStack.Num() - parms;
if ( !skipNextStatement ) {
PrintTabs();
}
output->Printf( "::Create%sThread%d( %s", s.op == OP_GUITHREAD ? "Gui" : "", index, program->scriptExporter.BuildGlobalFunctionName( f ) );
if ( parms > 0 ) {
output->Printf( ", " );
for ( int i = 0; i < parms; i++ ) {
PrintVariable( compileStack[ base + i ], f->type->GetParmType( i )->Type() );
if ( i != parms - 1 ) {
output->Printf( ", " );
}
}
}
output->Printf( " );\r\n" );
compileStack.SetNum( compileStack.Num() - parms );
return;
}
case OP_GUIOBJTHREAD:
case OP_OBJTHREAD: {
const function_t* f = s.c->value.functionPtr;
int parms = f->type->NumParameters();
assert( compileStack.Num() >= parms );
skipNextStatement = LookAheadStore( statement );
int base = compileStack.Num() - parms;
if ( !skipNextStatement ) {
PrintTabs();
}
sdScriptExporter::objectDef_t* o = program->scriptExporter.FindClass( nameSpace, f->def->scope->TypeDef() );
int index = program->scriptExporter.FindThreadCall( *o, f, s.op == OP_GUIOBJTHREAD );
PrintVariable( compileStack[ base ], f->type->GetParmType( 0 )->Type() );
output->Printf( "->Create%sThread%d( &%s::%s, \"%s\"", s.op == OP_GUIOBJTHREAD ? "Gui" : "", index, program->scriptExporter.BuildClassName( f->def->scope->TypeDef() ), f->type->Name(), f->type->Name() );
if ( parms > 1 ) {
output->Printf( ", " );
for ( int i = 1; i < parms; i++ ) {
PrintVariable( compileStack[ base + i ], f->type->GetParmType( i )->Type() );
if ( i != parms - 1 ) {
output->Printf( ", " );
}
}
}
output->Printf( " );\r\n" );
compileStack.SetNum( compileStack.Num() - parms );
return;
}
case OP_INDIRECT_F:
case OP_INDIRECT_V:
case OP_INDIRECT_S:
case OP_INDIRECT_W:
case OP_INDIRECT_BOOL:
case OP_INDIRECT_OBJ: {
CheckVariable( s.a );
CheckVariable( s.c, idCompiler::opcodes[ s.op ].type_c->Type() );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( "->" );
PrintField( s.a->TypeDef(), s.b );
output->Printf( ";\r\n" );
return;
}
case OP_RETURN: {
idVarDef* returnValue = NULL;
if ( func->function->type->ReturnType() != &type_void ) {
if ( s.a != NULL && !IsReturn( s.a ) ) {
returnValue = s.a;
} else {
if ( returnVar == NULL ) {
// Gordon: this is likely a dodgy automatically added return, so just skip
return;
}
returnValue = returnVar;
}
}
returnVar = NULL;
if ( isSpecial ) {
const sdScriptExporter::objectDef_t* cls = program->scriptExporter.FindClass( nameSpace, func->function->def->scope->TypeDef() );
for ( const sdScriptExporter::objectDef_t* o = cls->superType; o != NULL; o = o->superType ) {
for ( int i = 0; i < o->functions.Num(); i++ ) {
if ( idStr::Cmp( o->functions[ i ].function->type->Name(), func->function->type->Name() ) == 0 ) {
PrintTabs();
output->Printf( "%s::%s();\r\n", program->scriptExporter.BuildClassName( o->type ), func->function->type->Name() );
goto done;
}
}
}
}
done:
PrintTabs();
output->Printf( "return" );
if ( func->function->type->ReturnType() != &type_void ) {
output->Printf( " " );
PrintVariable( returnValue, func->function->type->ReturnType()->Type() );
idTypeDef* setType = func->function->type->ReturnType();
idTypeDef* getType = returnValue->TypeDef();
if ( setType != getType && setType->Inherits( getType ) ) {
output->Printf( "->Cast< %s >()", program->scriptExporter.BuildClassName( setType ) );
}
}
output->Printf( ";\r\n" );
return;
}
case OP_ALLOC_TYPE: {
CheckVariable( s.c );
PrintTabs();
PrintVariable( s.c, TYPE_OF( type_c ) );
output->Printf( " = compilerInterface->AllocObject( \"%s\" );\r\n", s.a->Name() );
return;
}
case OP_FREE_TYPE: {
PrintTabs();
output->Printf( "compilerInterface->FreeObject( " );
PrintVariable( s.a, TYPE_OF( type_a ) );
output->Printf( " );\r\n" );
return;
}
}
assert( false );
output->Printf( "//" );
program->DisassembleStatement( output, statement );
}