2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "../Game_local.h"
34 // simple types. function types are dynamically allocated
35 idTypeDef type_void( ev_void, &def_void, "void", 0, NULL );
36 idTypeDef type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( void * ), NULL );
37 idTypeDef type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( void * ), NULL );
38 idTypeDef type_string( ev_string, &def_string, "string", MAX_STRING_LEN, NULL );
39 idTypeDef type_float( ev_float, &def_float, "float", sizeof( float ), NULL );
40 idTypeDef type_vector( ev_vector, &def_vector, "vector", sizeof( idVec3 ), NULL );
41 idTypeDef type_entity( ev_entity, &def_entity, "entity", sizeof( int * ), NULL ); // stored as entity number pointer
42 idTypeDef type_field( ev_field, &def_field, "field", sizeof( void * ), NULL );
43 idTypeDef type_function( ev_function, &def_function, "function", sizeof( void * ), &type_void );
44 idTypeDef type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( int ), NULL );
45 idTypeDef type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( void * ), NULL );
46 idTypeDef type_object( ev_object, &def_object, "object", sizeof( int * ), NULL ); // stored as entity number pointer
47 idTypeDef type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "<jump>", sizeof( int ), NULL ); // only used for jump opcodes
48 idTypeDef type_argsize( ev_argsize, &def_argsize, "<argsize>", sizeof( int ), NULL ); // only used for function call and thread opcodes
49 idTypeDef type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( int ), NULL );
51 idVarDef def_void( &type_void );
52 idVarDef def_scriptevent( &type_scriptevent );
53 idVarDef def_namespace( &type_namespace );
54 idVarDef def_string( &type_string );
55 idVarDef def_float( &type_float );
56 idVarDef def_vector( &type_vector );
57 idVarDef def_entity( &type_entity );
58 idVarDef def_field( &type_field );
59 idVarDef def_function( &type_function );
60 idVarDef def_virtualfunction( &type_virtualfunction );
61 idVarDef def_pointer( &type_pointer );
62 idVarDef def_object( &type_object );
63 idVarDef def_jumpoffset( &type_jumpoffset ); // only used for jump opcodes
64 idVarDef def_argsize( &type_argsize );
65 idVarDef def_boolean( &type_boolean );
67 /***********************************************************************
71 ***********************************************************************/
75 function_t::function_t
78 function_t::function_t() {
87 size_t function_t::Allocated( void ) const {
88 return name.Allocated() + parmSize.Allocated();
96 void function_t::SetName( const char *name ) {
105 const char *function_t::Name( void ) const {
114 void function_t::Clear( void ) {
127 /***********************************************************************
131 ***********************************************************************/
138 idTypeDef::idTypeDef( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ) {
145 parmTypes.SetGranularity( 1 );
146 parmNames.SetGranularity( 1 );
147 functions.SetGranularity( 1 );
155 idTypeDef::idTypeDef( const idTypeDef &other ) {
164 void idTypeDef::operator=( const idTypeDef& other ) {
169 auxType = other.auxType;
170 parmTypes = other.parmTypes;
171 parmNames = other.parmNames;
172 functions = other.functions;
180 size_t idTypeDef::Allocated( void ) const {
184 memsize = name.Allocated() + parmTypes.Allocated() + parmNames.Allocated() + functions.Allocated();
185 for( i = 0; i < parmTypes.Num(); i++ ) {
186 memsize += parmNames[ i ].Allocated();
196 Returns true if basetype is an ancestor of this type.
199 bool idTypeDef::Inherits( const idTypeDef *basetype ) const {
200 idTypeDef *superType;
202 if ( type != ev_object ) {
206 if ( this == basetype ) {
209 for( superType = auxType; superType != NULL; superType = superType->auxType ) {
210 if ( superType == basetype ) {
220 idTypeDef::MatchesType
222 Returns true if both types' base types and parameters match
225 bool idTypeDef::MatchesType( const idTypeDef &matchtype ) const {
228 if ( this == &matchtype ) {
232 if ( ( type != matchtype.type ) || ( auxType != matchtype.auxType ) ) {
236 if ( parmTypes.Num() != matchtype.parmTypes.Num() ) {
240 for( i = 0; i < matchtype.parmTypes.Num(); i++ ) {
241 if ( parmTypes[ i ] != matchtype.parmTypes[ i ] ) {
251 idTypeDef::MatchesVirtualFunction
253 Returns true if both functions' base types and parameters match
256 bool idTypeDef::MatchesVirtualFunction( const idTypeDef &matchfunc ) const {
259 if ( this == &matchfunc ) {
263 if ( ( type != matchfunc.type ) || ( auxType != matchfunc.auxType ) ) {
267 if ( parmTypes.Num() != matchfunc.parmTypes.Num() ) {
271 if ( parmTypes.Num() > 0 ) {
272 if ( !parmTypes[ 0 ]->Inherits( matchfunc.parmTypes[ 0 ] ) ) {
277 for( i = 1; i < matchfunc.parmTypes.Num(); i++ ) {
278 if ( parmTypes[ i ] != matchfunc.parmTypes[ i ] ) {
288 idTypeDef::AddFunctionParm
290 Adds a new parameter for a function type.
293 void idTypeDef::AddFunctionParm( idTypeDef *parmtype, const char *name ) {
294 if ( type != ev_function ) {
295 throw idCompileError( "idTypeDef::AddFunctionParm : tried to add parameter on non-function type" );
298 parmTypes.Append( parmtype );
299 idStr &parmName = parmNames.Alloc();
307 Adds a new field to an object type.
310 void idTypeDef::AddField( idTypeDef *fieldtype, const char *name ) {
311 if ( type != ev_object ) {
312 throw idCompileError( "idTypeDef::AddField : tried to add field to non-object type" );
315 parmTypes.Append( fieldtype );
316 idStr &parmName = parmNames.Alloc();
319 if ( fieldtype->FieldType()->Inherits( &type_object ) ) {
320 size += type_object.Size();
322 size += fieldtype->FieldType()->Size();
331 void idTypeDef::SetName( const char *newname ) {
340 const char *idTypeDef::Name( void ) const {
349 etype_t idTypeDef::Type( void ) const {
358 int idTypeDef::Size( void ) const {
364 idTypeDef::SuperClass
366 If type is an object, then returns the object's superclass
369 idTypeDef *idTypeDef::SuperClass( void ) const {
370 if ( type != ev_object ) {
371 throw idCompileError( "idTypeDef::SuperClass : tried to get superclass of a non-object type" );
379 idTypeDef::ReturnType
381 If type is a function, then returns the function's return type
384 idTypeDef *idTypeDef::ReturnType( void ) const {
385 if ( type != ev_function ) {
386 throw idCompileError( "idTypeDef::ReturnType: tried to get return type on non-function type" );
394 idTypeDef::SetReturnType
396 If type is a function, then sets the function's return type
399 void idTypeDef::SetReturnType( idTypeDef *returntype ) {
400 if ( type != ev_function ) {
401 throw idCompileError( "idTypeDef::SetReturnType: tried to set return type on non-function type" );
404 auxType = returntype;
411 If type is a field, then returns it's type
414 idTypeDef *idTypeDef::FieldType( void ) const {
415 if ( type != ev_field ) {
416 throw idCompileError( "idTypeDef::FieldType: tried to get field type on non-field type" );
424 idTypeDef::SetFieldType
426 If type is a field, then sets the function's return type
429 void idTypeDef::SetFieldType( idTypeDef *fieldtype ) {
430 if ( type != ev_field ) {
431 throw idCompileError( "idTypeDef::SetFieldType: tried to set return type on non-function type" );
439 idTypeDef::PointerType
441 If type is a pointer, then returns the type it points to
444 idTypeDef *idTypeDef::PointerType( void ) const {
445 if ( type != ev_pointer ) {
446 throw idCompileError( "idTypeDef::PointerType: tried to get pointer type on non-pointer" );
454 idTypeDef::SetPointerType
456 If type is a pointer, then sets the pointer's type
459 void idTypeDef::SetPointerType( idTypeDef *pointertype ) {
460 if ( type != ev_pointer ) {
461 throw idCompileError( "idTypeDef::SetPointerType: tried to set type on non-pointer" );
464 auxType = pointertype;
469 idTypeDef::NumParameters
472 int idTypeDef::NumParameters( void ) const {
473 return parmTypes.Num();
478 idTypeDef::GetParmType
481 idTypeDef *idTypeDef::GetParmType( int parmNumber ) const {
482 assert( parmNumber >= 0 );
483 assert( parmNumber < parmTypes.Num() );
484 return parmTypes[ parmNumber ];
489 idTypeDef::GetParmName
492 const char *idTypeDef::GetParmName( int parmNumber ) const {
493 assert( parmNumber >= 0 );
494 assert( parmNumber < parmTypes.Num() );
495 return parmNames[ parmNumber ];
500 idTypeDef::NumFunctions
503 int idTypeDef::NumFunctions( void ) const {
504 return functions.Num();
509 idTypeDef::GetFunctionNumber
512 int idTypeDef::GetFunctionNumber( const function_t *func ) const {
515 for( i = 0; i < functions.Num(); i++ ) {
516 if ( functions[ i ] == func ) {
525 idTypeDef::GetFunction
528 const function_t *idTypeDef::GetFunction( int funcNumber ) const {
529 assert( funcNumber >= 0 );
530 assert( funcNumber < functions.Num() );
531 return functions[ funcNumber ];
536 idTypeDef::AddFunction
539 void idTypeDef::AddFunction( const function_t *func ) {
542 for( i = 0; i < functions.Num(); i++ ) {
543 if ( !strcmp( functions[ i ]->def->Name(), func->def->Name() ) ) {
544 if ( func->def->TypeDef()->MatchesVirtualFunction( *functions[ i ]->def->TypeDef() ) ) {
545 functions[ i ] = func;
550 functions.Append( func );
553 /***********************************************************************
557 ***********************************************************************/
564 idVarDef::idVarDef( idTypeDef *typeptr ) {
569 initialized = idVarDef::uninitialized;
570 memset( &value, 0, sizeof( value ) );
580 idVarDef::~idVarDef() {
582 name->RemoveDef( this );
591 const char *idVarDef::Name( void ) const {
600 const char *idVarDef::GlobalName( void ) const {
601 if ( scope != &def_namespace ) {
602 return va( "%s::%s", scope->GlobalName(), name->Name() );
610 idVarDef::DepthOfScope
613 int idVarDef::DepthOfScope( const idVarDef *otherScope ) const {
618 for( def = otherScope; def != NULL; def = def->scope ) {
619 if ( def == scope ) {
630 idVarDef::SetFunction
633 void idVarDef::SetFunction( function_t *func ) {
635 initialized = initializedConstant;
636 assert( typeDef->Type() == ev_function );
637 value.functionPtr = func;
645 void idVarDef::SetObject( idScriptObject *object ) {
647 initialized = initialized;
648 assert( typeDef->Inherits( &type_object ) );
649 *value.objectPtrPtr = object;
657 void idVarDef::SetValue( const eval_t &_value, bool constant ) {
660 initialized = initializedConstant;
662 initialized = initializedVariable;
665 switch( typeDef->Type() ) {
669 *value.intPtr = _value._int;
673 value.jumpOffset = _value._int;
677 value.argSize = _value._int;
681 *value.entityNumberPtr = _value.entity;
685 idStr::Copynz( value.stringPtr, _value.stringPtr, MAX_STRING_LEN );
689 *value.floatPtr = _value._float;
693 value.vectorPtr->x = _value.vector[ 0 ];
694 value.vectorPtr->y = _value.vector[ 1 ];
695 value.vectorPtr->z = _value.vector[ 2 ];
699 value.functionPtr = _value.function;
702 case ev_virtualfunction :
703 value.virtualFunction = _value._int;
707 *value.entityNumberPtr = _value.entity;
711 throw idCompileError( va( "weird type on '%s'", Name() ) );
721 void idVarDef::SetString( const char *string, bool constant ) {
723 initialized = initializedConstant;
725 initialized = initializedVariable;
728 assert( typeDef && ( typeDef->Type() == ev_string ) );
729 idStr::Copynz( value.stringPtr, string, MAX_STRING_LEN );
737 void idVarDef::PrintInfo( idFile *file, int instructionPointer ) const {
745 if ( initialized == initializedConstant ) {
746 file->Printf( "const " );
749 etype = typeDef->Type();
752 jumpto = instructionPointer + value.jumpOffset;
753 jumpst = &gameLocal.program.GetStatement( jumpto );
754 file->Printf( "address %d [%s(%d)]", jumpto, gameLocal.program.GetFilename( jumpst->file ), jumpst->linenumber );
758 if ( value.functionPtr->eventdef ) {
759 file->Printf( "event %s", GlobalName() );
761 file->Printf( "function %s", GlobalName() );
766 file->Printf( "field %d", value.ptrOffset );
770 file->Printf( "args %d", value.argSize );
774 file->Printf( "%s ", typeDef->Name() );
775 if ( initialized == initializedConstant ) {
778 file->Printf( "\"" );
779 len = strlen( value.stringPtr );
780 ch = value.stringPtr;
781 for( i = 0; i < len; i++, ch++ ) {
782 if ( idStr::CharIsPrintable( *ch ) ) {
783 file->Printf( "%c", *ch );
784 } else if ( *ch == '\n' ) {
785 file->Printf( "\\n" );
787 file->Printf( "\\x%.2x", static_cast<int>( *ch ) );
790 file->Printf( "\"" );
794 file->Printf( "'%s'", value.vectorPtr->ToString() );
798 file->Printf( "%f", *value.floatPtr );
801 case ev_virtualfunction :
802 file->Printf( "vtable[ %d ]", value.virtualFunction );
806 file->Printf( "%d", *value.intPtr );
809 } else if ( initialized == stackVariable ) {
810 file->Printf( "stack[%d]", value.stackOffset );
812 file->Printf( "global[%d]", num );
818 /***********************************************************************
822 ***********************************************************************/
829 void idVarDefName::AddDef( idVarDef *def ) {
830 assert( def->next == NULL );
838 idVarDefName::RemoveDef
841 void idVarDefName::RemoveDef( idVarDef *def ) {
845 for ( idVarDef *d = defs; d->next != NULL; d = d->next ) {
846 if ( d->next == def ) {
856 /***********************************************************************
860 ***********************************************************************/
864 idScriptObject::idScriptObject
867 idScriptObject::idScriptObject() {
874 idScriptObject::~idScriptObject
877 idScriptObject::~idScriptObject() {
886 void idScriptObject::Free( void ) {
900 void idScriptObject::Save( idSaveGame *savefile ) const {
903 if ( type == &type_object && data == NULL ) {
904 // Write empty string for uninitialized object
905 savefile->WriteString( "" );
907 savefile->WriteString( type->Name() );
909 savefile->WriteInt( size );
910 savefile->Write( data, size );
916 idScriptObject::Restore
919 void idScriptObject::Restore( idRestoreGame *savefile ) {
923 savefile->ReadString( typeName );
925 // Empty string signals uninitialized object
926 if ( typeName.Length() == 0 ) {
930 if ( !SetType( typeName ) ) {
931 savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() );
934 savefile->ReadInt( (int &)size );
935 if ( size != type->Size() ) {
936 savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() );
939 savefile->Read( data, size );
944 idScriptObject::SetType
946 Allocates an object and initializes memory.
949 bool idScriptObject::SetType( const char *typeName ) {
954 newtype = gameLocal.program.FindType( typeName );
956 // only allocate memory if the object type changes
957 if ( newtype != type ) {
960 gameLocal.Warning( "idScriptObject::SetType: Unknown type '%s'", typeName );
964 if ( !newtype->Inherits( &type_object ) ) {
965 gameLocal.Warning( "idScriptObject::SetType: Can't create object of type '%s'. Must be an object type.", newtype->Name() );
972 // allocate the memory
974 data = ( byte * )Mem_Alloc( size );
977 // init object memory
985 idScriptObject::ClearObject
987 Resets the memory for the script object without changing its type.
990 void idScriptObject::ClearObject( void ) {
993 if ( type != &type_object ) {
994 // init object memory
996 memset( data, 0, size );
1002 idScriptObject::HasObject
1005 bool idScriptObject::HasObject( void ) const {
1006 return ( type != &type_object );
1011 idScriptObject::GetTypeDef
1014 idTypeDef *idScriptObject::GetTypeDef( void ) const {
1020 idScriptObject::GetTypeName
1023 const char *idScriptObject::GetTypeName( void ) const {
1024 return type->Name();
1029 idScriptObject::GetConstructor
1032 const function_t *idScriptObject::GetConstructor( void ) const {
1033 const function_t *func;
1035 func = GetFunction( "init" );
1041 idScriptObject::GetDestructor
1044 const function_t *idScriptObject::GetDestructor( void ) const {
1045 const function_t *func;
1047 func = GetFunction( "destroy" );
1053 idScriptObject::GetFunction
1056 const function_t *idScriptObject::GetFunction( const char *name ) const {
1057 const function_t *func;
1059 if ( type == &type_object ) {
1063 func = gameLocal.program.FindFunction( name, type );
1069 idScriptObject::GetVariable
1072 byte *idScriptObject::GetVariable( const char *name, etype_t etype ) const {
1076 const idTypeDef *parm;
1078 if ( type == &type_object ) {
1084 if ( t->SuperClass() != &type_object ) {
1085 pos = t->SuperClass()->Size();
1089 for( i = 0; i < t->NumParameters(); i++ ) {
1090 parm = t->GetParmType( i );
1091 if ( !strcmp( t->GetParmName( i ), name ) ) {
1092 if ( etype != parm->FieldType()->Type() ) {
1095 return &data[ pos ];
1098 if ( parm->FieldType()->Inherits( &type_object ) ) {
1099 pos += type_object.Size();
1101 pos += parm->FieldType()->Size();
1104 t = t->SuperClass();
1105 } while( t && ( t != &type_object ) );
1110 /***********************************************************************
1114 ***********************************************************************/
1118 idProgram::AllocType
1121 idTypeDef *idProgram::AllocType( idTypeDef &type ) {
1124 newtype = new idTypeDef( type );
1125 types.Append( newtype );
1132 idProgram::AllocType
1135 idTypeDef *idProgram::AllocType( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ) {
1138 newtype = new idTypeDef( etype, edef, ename, esize, aux );
1139 types.Append( newtype );
1148 Returns a preexisting complex type that matches the parm, or allocates
1149 a new one and copies it out.
1152 idTypeDef *idProgram::GetType( idTypeDef &type, bool allocate ) {
1155 //FIXME: linear search == slow
1156 for( i = types.Num() - 1; i >= 0; i-- ) {
1157 if ( types[ i ]->MatchesType( type ) && !strcmp( types[ i ]->Name(), type.Name() ) ) {
1166 // allocate a new one
1167 return AllocType( type );
1174 Returns a preexisting complex type that matches the name, or returns NULL if not found
1177 idTypeDef *idProgram::FindType( const char *name ) {
1181 for( i = types.Num() - 1; i >= 0; i-- ) {
1183 if ( !strcmp( check->Name(), name ) ) {
1193 idProgram::GetDefList
1196 idVarDef *idProgram::GetDefList( const char *name ) const {
1199 hash = varDefNameHash.GenerateKey( name, true );
1200 for ( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) ) {
1201 if ( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 ) {
1202 return varDefNames[i]->GetDefs();
1210 idProgram::AddDefToNameList
1213 void idProgram::AddDefToNameList( idVarDef *def, const char *name ) {
1216 hash = varDefNameHash.GenerateKey( name, true );
1217 for ( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) ) {
1218 if ( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 ) {
1223 i = varDefNames.Append( new idVarDefName( name ) );
1224 varDefNameHash.Add( hash, i );
1226 varDefNames[i]->AddDef( def );
1234 idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scope, bool constant ) {
1241 // allocate a new def
1242 def = new idVarDef( type );
1245 def->num = varDefs.Append( def );
1247 // add the def to the list with defs with this name and set the name pointer
1248 AddDefToNameList( def, name );
1250 if ( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) ) {
1254 if ( !strcmp( name, RESULT_STRING ) ) {
1255 // <RESULT> vector defs don't need the _x, _y and _z components
1256 assert( scope->Type() == ev_function );
1257 def->value.stackOffset = scope->value.functionPtr->locals;
1258 def->initialized = idVarDef::stackVariable;
1259 scope->value.functionPtr->locals += type->Size();
1260 } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
1261 idTypeDef newtype( ev_field, NULL, "float field", 0, &type_float );
1262 idTypeDef *type = GetType( newtype, true );
1264 // set the value to the variable's position in the object
1265 def->value.ptrOffset = scope->TypeDef()->Size();
1267 // make automatic defs for the vectors elements
1268 // origin can be accessed as origin_x, origin_y, and origin_z
1269 sprintf( element, "%s_x", def->Name() );
1270 def_x = AllocDef( type, element, scope, constant );
1272 sprintf( element, "%s_y", def->Name() );
1273 def_y = AllocDef( type, element, scope, constant );
1274 def_y->value.ptrOffset = def_x->value.ptrOffset + type_float.Size();
1276 sprintf( element, "%s_z", def->Name() );
1277 def_z = AllocDef( type, element, scope, constant );
1278 def_z->value.ptrOffset = def_y->value.ptrOffset + type_float.Size();
1280 // make automatic defs for the vectors elements
1281 // origin can be accessed as origin_x, origin_y, and origin_z
1282 sprintf( element, "%s_x", def->Name() );
1283 def_x = AllocDef( &type_float, element, scope, constant );
1285 sprintf( element, "%s_y", def->Name() );
1286 def_y = AllocDef( &type_float, element, scope, constant );
1288 sprintf( element, "%s_z", def->Name() );
1289 def_z = AllocDef( &type_float, element, scope, constant );
1291 // point the vector def to the x coordinate
1292 def->value = def_x->value;
1293 def->initialized = def_x->initialized;
1295 } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
1299 // set the value to the variable's position in the object
1300 def->value.ptrOffset = scope->TypeDef()->Size();
1301 } else if ( scope->Type() == ev_function ) {
1305 // since we don't know how many local variables there are,
1306 // we have to have them go backwards on the stack
1307 def->value.stackOffset = scope->value.functionPtr->locals;
1308 def->initialized = idVarDef::stackVariable;
1310 if ( type->Inherits( &type_object ) ) {
1311 // objects only have their entity number on the stack, not the entire object
1312 scope->value.functionPtr->locals += type_object.Size();
1314 scope->value.functionPtr->locals += type->Size();
1320 def->value.bytePtr = &variables[ numVariables ];
1321 numVariables += def->TypeDef()->Size();
1322 if ( numVariables > sizeof( variables ) ) {
1323 throw idCompileError( va( "Exceeded global memory size (%d bytes)", sizeof( variables ) ) );
1326 memset( def->value.bytePtr, 0, def->TypeDef()->Size() );
1336 If type is NULL, it will match any type
1339 idVarDef *idProgram::GetDef( const idTypeDef *type, const char *name, const idVarDef *scope ) const {
1347 for( def = GetDefList( name ); def != NULL; def = def->Next() ) {
1348 if ( def->scope->Type() == ev_namespace ) {
1349 depth = def->DepthOfScope( scope );
1351 // not in the same namespace
1354 } else if ( def->scope != scope ) {
1355 // in a different function
1361 if ( !bestDef || ( depth < bestDepth ) ) {
1367 // see if the name is already in use for another type
1368 if ( bestDef && type && ( bestDef->TypeDef() != type ) ) {
1369 throw idCompileError( va( "Type mismatch on redeclaration of %s", name ) );
1380 void idProgram::FreeDef( idVarDef *def, const idVarDef *scope ) {
1384 if ( def->Type() == ev_vector ) {
1387 sprintf( name, "%s_x", def->Name() );
1388 e = GetDef( NULL, name, scope );
1390 FreeDef( e, scope );
1393 sprintf( name, "%s_y", def->Name() );
1394 e = GetDef( NULL, name, scope );
1396 FreeDef( e, scope );
1399 sprintf( name, "%s_z", def->Name() );
1400 e = GetDef( NULL, name, scope );
1402 FreeDef( e, scope );
1406 varDefs.RemoveIndex( def->num );
1407 for( i = def->num; i < varDefs.Num(); i++ ) {
1408 varDefs[ i ]->num = i;
1416 idProgram::FindFreeResultDef
1419 idVarDef *idProgram::FindFreeResultDef( idTypeDef *type, const char *name, idVarDef *scope, const idVarDef *a, const idVarDef *b ) {
1422 for( def = GetDefList( name ); def != NULL; def = def->Next() ) {
1423 if ( def == a || def == b ) {
1426 if ( def->TypeDef() != type ) {
1429 if ( def->scope != scope ) {
1432 if ( def->numUsers <= 1 ) {
1438 return AllocDef( type, name, scope, false );
1443 idProgram::FindFunction
1445 Searches for the specified function in the currently loaded script. A full namespace should be
1446 specified if not in the global namespace.
1448 Returns 0 if function not found.
1449 Returns >0 if function found.
1452 function_t *idProgram::FindFunction( const char *name ) const {
1455 idVarDef *namespaceDef;
1460 idStr fullname = name;
1462 namespaceDef = &def_namespace;
1464 pos = fullname.Find( "::", true, start );
1469 idStr namespaceName = fullname.Mid( start, pos - start );
1470 def = GetDef( NULL, namespaceName, namespaceDef );
1472 // couldn't find namespace
1479 } while( def->Type() == ev_namespace );
1481 idStr funcName = fullname.Right( fullname.Length() - start );
1482 def = GetDef( NULL, funcName, namespaceDef );
1484 // couldn't find function
1488 if ( ( def->Type() == ev_function ) && ( def->value.functionPtr->eventdef == NULL ) ) {
1489 return def->value.functionPtr;
1492 // is not a function, or is an eventdef
1498 idProgram::FindFunction
1500 Searches for the specified object function in the currently loaded script.
1502 Returns 0 if function not found.
1503 Returns >0 if function found.
1506 function_t *idProgram::FindFunction( const char *name, const idTypeDef *type ) const {
1507 const idVarDef *tdef;
1508 const idVarDef *def;
1510 // look for the function
1512 for( tdef = type->def; tdef != &def_object; tdef = tdef->TypeDef()->SuperClass()->def ) {
1513 def = GetDef( NULL, name, tdef );
1515 return def->value.functionPtr;
1524 idProgram::AllocFunction
1527 function_t &idProgram::AllocFunction( idVarDef *def ) {
1528 if ( functions.Num() >= functions.Max() ) {
1529 throw idCompileError( va( "Exceeded maximum allowed number of functions (%d)", functions.Max() ) );
1532 // fill in the dfunction
1533 function_t &func = *functions.Alloc();
1534 func.eventdef = NULL;
1536 func.type = def->TypeDef();
1537 func.firstStatement = 0;
1538 func.numStatements = 0;
1541 func.filenum = filenum;
1542 func.parmSize.SetGranularity( 1 );
1543 func.SetName( def->GlobalName() );
1545 def->SetFunction( &func );
1552 idProgram::SetEntity
1555 void idProgram::SetEntity( const char *name, idEntity *ent ) {
1557 idStr defName( "$" );
1561 def = GetDef( &type_entity, defName, &def_namespace );
1562 if ( def && ( def->initialized != idVarDef::stackVariable ) ) {
1563 // 0 is reserved for NULL entity
1565 *def->value.entityNumberPtr = 0;
1567 *def->value.entityNumberPtr = ent->entityNumber + 1;
1574 idProgram::AllocStatement
1577 statement_t *idProgram::AllocStatement( void ) {
1578 if ( statements.Num() >= statements.Max() ) {
1579 throw idCompileError( va( "Exceeded maximum allowed number of statements (%d)", statements.Max() ) );
1581 return statements.Alloc();
1586 idProgram::BeginCompilation
1588 called before compiling a batch of files, clears the pr struct
1591 void idProgram::BeginCompilation( void ) {
1592 statement_t *statement;
1597 // make the first statement a return for a "NULL" function
1598 statement = AllocStatement();
1599 statement->linenumber = 0;
1600 statement->file = 0;
1601 statement->op = OP_RETURN;
1602 statement->a = NULL;
1603 statement->b = NULL;
1604 statement->c = NULL;
1607 //AllocDef( &type_void, "<NULL>", &def_namespace, true );
1609 // define the return def
1610 returnDef = AllocDef( &type_vector, "<RETURN>", &def_namespace, false );
1612 // define the return def for strings
1613 returnStringDef = AllocDef( &type_string, "<RETURN>", &def_namespace, false );
1615 // define the sys object
1616 sysDef = AllocDef( &type_void, "sys", &def_namespace, true );
1619 catch( idCompileError &err ) {
1620 gameLocal.Error( "%s", err.error );
1626 idProgram::DisassembleStatement
1629 void idProgram::DisassembleStatement( idFile *file, int instructionPointer ) const {
1631 const statement_t *statement;
1633 statement = &statements[ instructionPointer ];
1634 op = &idCompiler::opcodes[ statement->op ];
1635 file->Printf( "%20s(%d):\t%6d: %15s\t", fileList[ statement->file ].c_str(), statement->linenumber, instructionPointer, op->opname );
1637 if ( statement->a ) {
1638 file->Printf( "\ta: " );
1639 statement->a->PrintInfo( file, instructionPointer );
1642 if ( statement->b ) {
1643 file->Printf( "\tb: " );
1644 statement->b->PrintInfo( file, instructionPointer );
1647 if ( statement->c ) {
1648 file->Printf( "\tc: " );
1649 statement->c->PrintInfo( file, instructionPointer );
1652 file->Printf( "\n" );
1657 idProgram::Disassemble
1660 void idProgram::Disassemble( void ) const {
1662 int instructionPointer;
1663 const function_t *func;
1666 file = fileSystem->OpenFileByMode( "script/disasm.txt", FS_WRITE );
1668 for( i = 0; i < functions.Num(); i++ ) {
1669 func = &functions[ i ];
1670 if ( func->eventdef ) {
1675 file->Printf( "\nfunction %s() %d stack used, %d parms, %d locals {\n", func->Name(), func->locals, func->parmTotal, func->locals - func->parmTotal );
1677 for( instructionPointer = 0; instructionPointer < func->numStatements; instructionPointer++ ) {
1678 DisassembleStatement( file, func->firstStatement + instructionPointer );
1681 file->Printf( "}\n" );
1684 fileSystem->CloseFile( file );
1689 idProgram::FinishCompilation
1691 Called after all files are compiled to check for errors
1694 void idProgram::FinishCompilation( void ) {
1697 top_functions = functions.Num();
1698 top_statements = statements.Num();
1699 top_types = types.Num();
1700 top_defs = varDefs.Num();
1701 top_files = fileList.Num();
1703 variableDefaults.Clear();
1704 variableDefaults.SetNum( numVariables );
1706 for( i = 0; i < numVariables; i++ ) {
1707 variableDefaults[ i ] = variables[ i ];
1713 idProgram::CompileStats
1715 called after all files are compiled to report memory usage.
1718 void idProgram::CompileStats( void ) {
1726 gameLocal.Printf( "---------- Compile stats ----------\n" );
1727 gameLocal.DPrintf( "Files loaded:\n" );
1730 for( i = 0; i < fileList.Num(); i++ ) {
1731 gameLocal.DPrintf( " %s\n", fileList[ i ].c_str() );
1732 stringspace += fileList[ i ].Allocated();
1734 stringspace += fileList.Size();
1736 numdefs = varDefs.Num();
1737 memused = varDefs.Num() * sizeof( idVarDef );
1738 memused += types.Num() * sizeof( idTypeDef );
1739 memused += stringspace;
1741 for( i = 0; i < types.Num(); i++ ) {
1742 memused += types[ i ]->Allocated();
1745 funcMem = functions.MemoryUsed();
1746 for( i = 0; i < functions.Num(); i++ ) {
1747 funcMem += functions[ i ].Allocated();
1750 memallocated = funcMem + memused + sizeof( idProgram );
1752 memused += statements.MemoryUsed();
1753 memused += functions.MemoryUsed(); // name and filename of functions are shared, so no need to include them
1754 memused += sizeof( variables );
1756 gameLocal.Printf( "\nMemory usage:\n" );
1757 gameLocal.Printf( " Strings: %d, %d bytes\n", fileList.Num(), stringspace );
1758 gameLocal.Printf( " Statements: %d, %d bytes\n", statements.Num(), statements.MemoryUsed() );
1759 gameLocal.Printf( " Functions: %d, %d bytes\n", functions.Num(), funcMem );
1760 gameLocal.Printf( " Variables: %d bytes\n", numVariables );
1761 gameLocal.Printf( " Mem used: %d bytes\n", memused );
1762 gameLocal.Printf( " Static data: %d bytes\n", sizeof( idProgram ) );
1763 gameLocal.Printf( " Allocated: %d bytes\n", memallocated );
1764 gameLocal.Printf( " Thread size: %d bytes\n\n", sizeof( idThread ) );
1769 idProgram::CompileText
1772 bool idProgram::CompileText( const char *source, const char *text, bool console ) {
1773 idCompiler compiler;
1778 // use a full os path for GetFilenum since it calls OSPathToRelativePath to convert filenames from the parser
1779 ospath = fileSystem->RelativePathToOSPath( source );
1780 filenum = GetFilenum( ospath );
1783 compiler.CompileFile( text, filename, console );
1785 // check to make sure all functions prototyped have code
1786 for( i = 0; i < varDefs.Num(); i++ ) {
1788 if ( ( def->Type() == ev_function ) && ( ( def->scope->Type() == ev_namespace ) || def->scope->TypeDef()->Inherits( &type_object ) ) ) {
1789 if ( !def->value.functionPtr->eventdef && !def->value.functionPtr->firstStatement ) {
1790 throw idCompileError( va( "function %s was not defined\n", def->GlobalName() ) );
1796 catch( idCompileError &err ) {
1798 gameLocal.Printf( "%s\n", err.error );
1801 gameLocal.Error( "%s\n", err.error );
1814 idProgram::CompileFunction
1817 const function_t *idProgram::CompileFunction( const char *functionName, const char *text ) {
1820 result = CompileText( functionName, text, false );
1822 if ( g_disasm.GetBool() ) {
1827 gameLocal.Error( "Compile failed." );
1830 return FindFunction( functionName );
1835 idProgram::CompileFile
1838 void idProgram::CompileFile( const char *filename ) {
1842 if ( fileSystem->ReadFile( filename, ( void ** )&src, NULL ) < 0 ) {
1843 gameLocal.Error( "Couldn't load %s\n", filename );
1846 result = CompileText( filename, src, false );
1848 fileSystem->FreeFile( src );
1850 if ( g_disasm.GetBool() ) {
1855 gameLocal.Error( "Compile failed in file %s.", filename );
1864 void idProgram::FreeData( void ) {
1868 varDefs.DeleteContents( true );
1869 varDefNames.DeleteContents( true );
1870 varDefNameHash.Free();
1873 returnStringDef = NULL;
1876 // free any special types we've created
1877 types.DeleteContents( true );
1882 memset( variables, 0, sizeof( variables ) );
1884 // clear all the strings in the functions so that it doesn't look like we're leaking memory.
1885 for( i = 0; i < functions.Num(); i++ ) {
1886 functions[ i ].Clear();
1908 void idProgram::Startup( const char *defaultScript ) {
1909 gameLocal.Printf( "Initializing scripts\n" );
1911 // make sure all data is freed up
1912 idThread::Restart();
1914 // get ready for loading scripts
1917 // load the default script
1918 if ( defaultScript && *defaultScript ) {
1919 CompileFile( defaultScript );
1922 FinishCompilation();
1930 void idProgram::Save( idSaveGame *savefile ) const {
1932 int currentFileNum = top_files;
1934 savefile->WriteInt( (fileList.Num() - currentFileNum) );
1935 while ( currentFileNum < fileList.Num() ) {
1936 savefile->WriteString( fileList[ currentFileNum ] );
1940 for ( i = 0; i < variableDefaults.Num(); i++ ) {
1941 if ( variables[i] != variableDefaults[i] ) {
1942 savefile->WriteInt( i );
1943 savefile->WriteByte( variables[i] );
1946 // Mark the end of the diff with default variables with -1
1947 savefile->WriteInt( -1 );
1949 savefile->WriteInt( numVariables );
1950 for ( i = variableDefaults.Num(); i < numVariables; i++ ) {
1951 savefile->WriteByte( variables[i] );
1954 int checksum = CalculateChecksum();
1955 savefile->WriteInt( checksum );
1963 bool idProgram::Restore( idRestoreGame *savefile ) {
1968 savefile->ReadInt( num );
1969 for ( i = 0; i < num; i++ ) {
1970 savefile->ReadString( scriptname );
1971 CompileFile( scriptname );
1974 savefile->ReadInt( index );
1975 while( index >= 0 ) {
1976 savefile->ReadByte( variables[index] );
1977 savefile->ReadInt( index );
1980 savefile->ReadInt( num );
1981 for ( i = variableDefaults.Num(); i < num; i++ ) {
1982 savefile->ReadByte( variables[i] );
1985 int saved_checksum, checksum;
1987 savefile->ReadInt( saved_checksum );
1988 checksum = CalculateChecksum();
1990 if ( saved_checksum != checksum ) {
1999 idProgram::CalculateChecksum
2002 int idProgram::CalculateChecksum( void ) const {
2010 unsigned short linenumber;
2011 unsigned short file;
2014 statementBlock_t *statementList = new statementBlock_t[ statements.Num() ];
2016 memset( statementList, 0, ( sizeof(statementBlock_t) * statements.Num() ) );
2018 // Copy info into new list, using the variable numbers instead of a pointer to the variable
2019 for( i = 0; i < statements.Num(); i++ ) {
2020 statementList[i].op = statements[i].op;
2022 if ( statements[i].a ) {
2023 statementList[i].a = statements[i].a->num;
2025 statementList[i].a = -1;
2027 if ( statements[i].b ) {
2028 statementList[i].b = statements[i].b->num;
2030 statementList[i].b = -1;
2032 if ( statements[i].c ) {
2033 statementList[i].c = statements[i].c->num;
2035 statementList[i].c = -1;
2038 statementList[i].linenumber = statements[i].linenumber;
2039 statementList[i].file = statements[i].file;
2042 result = MD4_BlockChecksum( statementList, ( sizeof(statementBlock_t) * statements.Num() ) );
2044 delete [] statementList;
2053 Restores all variables to their initial value
2056 void idProgram::Restart( void ) {
2059 idThread::Restart();
2062 // since there may have been a script loaded by the map or the user may
2063 // have typed "script" from the console, free up any types and vardefs that
2064 // have been allocated after the initial startup
2066 for( i = top_types; i < types.Num(); i++ ) {
2069 types.SetNum( top_types, false );
2071 for( i = top_defs; i < varDefs.Num(); i++ ) {
2072 delete varDefs[ i ];
2074 varDefs.SetNum( top_defs, false );
2076 for( i = top_functions; i < functions.Num(); i++ ) {
2077 functions[ i ].Clear();
2079 functions.SetNum( top_functions );
2081 statements.SetNum( top_statements );
2082 fileList.SetNum( top_files, false );
2085 // reset the variables to their default values
2086 numVariables = variableDefaults.Num();
2087 for( i = 0; i < numVariables; i++ ) {
2088 variables[ i ] = variableDefaults[ i ];
2094 idProgram::GetFilenum
2097 int idProgram::GetFilenum( const char *name ) {
2098 if ( filename == name ) {
2103 strippedName = fileSystem->OSPathToRelativePath( name );
2104 if ( !strippedName.Length() ) {
2105 // not off the base path so just use the full path
2106 filenum = fileList.AddUnique( name );
2108 filenum = fileList.AddUnique( strippedName );
2111 // save the unstripped name so that we don't have to strip the incoming name every time we call GetFilenum
2119 idProgram::idProgram
2122 idProgram::idProgram() {
2128 idProgram::~idProgram
2131 idProgram::~idProgram() {
2137 idProgram::ReturnEntity
2140 void idProgram::ReturnEntity( idEntity *ent ) {
2142 *returnDef->value.entityNumberPtr = ent->entityNumber + 1;
2144 *returnDef->value.entityNumberPtr = 0;