Torque3D Documentation / _generateds / engineXMLExport.cpp

engineXMLExport.cpp

Engine/source/console/engineXMLExport.cpp

A generator that will dump all export structures contained in an engine DLL to an XML file which may then be used by wrapper generators to create a language-specific binding for the engine API.

More...

Public Defines

define
PRIMTYPE(tp)             ( < tp >() == type )                                        \
            {                                                                 \
               tp val = < tp >( defaultArgs, offset );             \
               value = ( val );                               \
            }

Public Variables

Public Functions

DefineEngineFunction(exportEngineAPIToXML , SimXMLDocument * , () , "Create a XML document containing a dump of the entire exported engine <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">API.\n\n</a>" "@return A <a href="/coding/class/classsimxmldocument/">SimXMLDocument</a> containing a dump of the engine's export information or <a href="/coding/file/typesx86unix_8h/#typesx86unix_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a> <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the operation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">failed.\n\n</a>" "@ingroup Console" )
exportScope(const EngineExportScope * scope, SimXMLDocument * xml, bool addNode)
const char *
bool

Helper to parse argument names out of a prototype string.

Detailed Description

A generator that will dump all export structures contained in an engine DLL to an XML file which may then be used by wrapper generators to create a language-specific binding for the engine API.

Using XML as an intermediary format allows the generators to use all of the export structures without actually having to access them directly in the DLL as native entities.

Public Defines

PRIMTYPE(tp)             ( < tp >() == type )                                        \
            {                                                                 \
               tp val = < tp >( defaultArgs, offset );             \
               value = ( val );                               \
            }

Public Variables

const char * sExportFilterList []

Public Functions

DefineEngineFunction(exportEngineAPIToXML , SimXMLDocument * , () , "Create a XML document containing a dump of the entire exported engine <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">API.\n\n</a>" "@return A <a href="/coding/class/classsimxmldocument/">SimXMLDocument</a> containing a dump of the engine's export information or <a href="/coding/file/typesx86unix_8h/#typesx86unix_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a> <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the operation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">failed.\n\n</a>" "@ingroup Console" )

exportFunction(const EngineFunctionInfo * function, SimXMLDocument * xml)

exportScope(const EngineExportScope * scope, SimXMLDocument * xml, bool addNode)

exportType(const EngineTypeInfo * type, SimXMLDocument * xml)

getArgValue(const EngineFunctionDefaultArguments * defaultArgs, U32 offset)

getDefaultArgumentValue(const EngineFunctionInfo * function, const EngineTypeInfo * type, U32 offset)

getDocString(const EngineExport * exportInfo)

getTypeName(const EngineTypeInfo * type)

isExportFiltered(const EngineExport * exportInfo)

parseFunctionArgumentNames(const EngineFunctionInfo * function)

Helper to parse argument names out of a prototype string.

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "console/engineExports.h"
 25#include "console/engineAPI.h"
 26#include "console/engineTypes.h"
 27#include "console/engineFunctions.h"
 28#include "console/SimXMLDocument.h"
 29
 30
 31/// @file
 32/// A generator that will dump all export structures contained in an engine
 33/// DLL to an XML file which may then be used by wrapper generators to create a
 34/// language-specific binding for the engine API.  Using XML as an intermediary
 35/// format allows the generators to use all of the export structures without
 36/// actually having to access them directly in the DLL as native entities.
 37
 38
 39static void exportScope( const EngineExportScope* scope, SimXMLDocument* xml, bool addNode = false );
 40
 41
 42static String getTypeName( const EngineTypeInfo* type )
 43{
 44   if( !type )
 45   {
 46      static String sVoid( "void" );
 47      return sVoid;
 48   }
 49      
 50   return type->getFullyQualifiedExportName();
 51}
 52
 53static const char* getDocString( const EngineExport* exportInfo )
 54{
 55   if( !exportInfo->getDocString() )
 56      return "";
 57   
 58   return exportInfo->getDocString();
 59}
 60
 61template< typename T >
 62inline T getArgValue( const EngineFunctionDefaultArguments* defaultArgs, U32 offset )
 63{
 64   return *reinterpret_cast< const T* >( defaultArgs->getArgs() + offset );
 65}
 66
 67
 68// List of exports that we want filtered out.  This will only be needed as long
 69// as the console system is still around.
 70static const char* sExportFilterList[] =
 71{
 72   "Console", // Console namespace
 73};
 74
 75static bool isExportFiltered( const EngineExport* exportInfo )
 76{
 77   String qualifiedName = exportInfo->getFullyQualifiedExportName();
 78   
 79   for( U32 i = 0; i < ( sizeof( sExportFilterList ) / sizeof( sExportFilterList[ 0 ] ) ); ++ i )
 80      if( qualifiedName.compare( sExportFilterList[ i ] ) == 0 )
 81         return true;
 82         
 83   return false;
 84}
 85
 86//=============================================================================
 87//    Functions.
 88//=============================================================================
 89// MARK: ---- Functions ----
 90
 91//-----------------------------------------------------------------------------
 92
 93/// Helper to parse argument names out of a prototype string.
 94static Vector< String> parseFunctionArgumentNames( const EngineFunctionInfo* function )
 95{
 96   Vector< String> argNames;
 97   
 98   const char* prototype = function->getPrototypeString();
 99   if( !prototype )
100      return argNames;
101      
102   const U32 prototypeLength = dStrlen( prototype );
103   const char* prototypeEnd = &prototype[ prototypeLength ];
104   const char* ptr = prototypeEnd - 1;
105   
106   // Search for right parenthesis.
107   while( ptr >= prototype && *ptr != ')' )
108      ptr --;
109      
110   if( ptr < prototype )
111      return argNames;
112   ptr --;
113   
114   while( ptr >= prototype && *ptr != '(' )
115   {
116      // Skip back over spaces.
117      
118      while( ptr >= prototype && dIsspace( *ptr ) )
119         ptr --;
120      if( ptr < prototype )
121         return argNames;
122         
123      // Parse out name.
124      
125      const char* end = ptr + 1;
126      while( ptr > prototype && dIsalnum( *ptr ) )
127         ptr --;
128      const char* start = ptr + 1;
129               
130      // Skip back over spaces.
131
132      while( ptr >= prototype && dIsspace( *ptr ) )
133         ptr --;
134         
135      // If we're sure we don't have just a type name without an
136      // argument name, copy out the argument name name. 
137
138      if( ptr >= prototype && *ptr != ',' && *ptr != '(' && end > start )
139         argNames.push_front( String( start, end - start ) );
140      else
141         argNames.push_front( "" );
142      
143      // Skip back to comma or opening parenthesis.
144      
145      U32 parenNestingCount = 0;
146      while( ptr >= prototype )
147      {
148         if( *ptr == ')' )
149            parenNestingCount ++;
150         else if( *ptr == '(' )
151            parenNestingCount --;
152         else if( *ptr == ',' && parenNestingCount == 0 )
153         {
154            ptr --;
155            break;
156         }
157         else if( *ptr == '(' && parenNestingCount == 0 )
158            break;
159            
160         ptr --;
161      }
162   }
163   
164   // Add 'this' parameter if this is a method.
165      
166   if( dStrncmp( prototype, "virtual ", sizeof( "virtual " ) - 1 ) == 0 )
167      argNames.push_front( "this" );
168
169   return argNames;
170}
171
172//-----------------------------------------------------------------------------
173
174static String getDefaultArgumentValue( const EngineFunctionInfo* function, const EngineTypeInfo* type, U32 offset )
175{
176   String value;
177   const EngineFunctionDefaultArguments* defaultArgs = function->getDefaultArguments();
178   
179   switch( type->getTypeKind() )
180   {
181      case EngineTypeKindPrimitive:
182      {
183         #define PRIMTYPE( tp )                                               \
184            if( TYPE< tp >() == type )                                        \
185            {                                                                 \
186               tp val = getArgValue< tp >( defaultArgs, offset );             \
187               value = String::ToString( val );                               \
188            }
189            
190         PRIMTYPE( bool );
191         PRIMTYPE( S8 );
192         PRIMTYPE( U8 );
193         PRIMTYPE( S32 );
194         PRIMTYPE( U32 );
195         PRIMTYPE( F32 );
196         PRIMTYPE( F64 );
197         
198         //TODO: for now we store string literals in ASCII; needs to be sorted out
199         if( TYPE< const char*>() == type )
200         {
201            const char* val = getArgValue< const char* >( defaultArgs, offset );
202            value = val;
203         }
204            
205         #undef PRIMTYPE
206         break;
207      }
208         
209      case EngineTypeKindEnum:
210      {
211         S32 val = getArgValue< S32 >( defaultArgs, offset );
212         AssertFatal( type->getEnumTable(), "engineXMLExport - Enum type without table!" );
213         
214         const EngineEnumTable& table = *( type->getEnumTable() );
215         const U32 numValues = table.getNumValues();
216         
217         for( U32 i = 0; i < numValues; ++ i )
218            if( table[ i ].getInt() == val )
219            {
220               value = table[ i ].getName();
221               break;
222            }
223               
224         break;
225      }
226
227      case EngineTypeKindBitfield:
228      {
229         S32 val = getArgValue< S32 >( defaultArgs, offset );
230         AssertFatal( type->getEnumTable(), "engineXMLExport - Bitfield type without table!" );
231         
232         const EngineEnumTable& table = *( type->getEnumTable() );
233         const U32 numValues = table.getNumValues();
234         
235         bool isFirst = true;
236         for( U32 i = 0; i < numValues; ++ i )
237            if( table[ i ].getInt() & val )
238            {
239               if( !isFirst )
240                  value += '|';
241                  
242               value = table[ i ].getName();
243               isFirst = false;
244            }
245
246         break;
247      }
248      
249      case EngineTypeKindStruct:
250      {
251         //TODO: struct type default argument values
252         break;
253      }
254         
255      case EngineTypeKindClass:
256      case EngineTypeKindFunction:
257      {
258         // For these two kinds, we support "null" as the only valid
259         // default value.
260         
261         const void* ptr = getArgValue< const void* >( defaultArgs, offset );
262         if( !ptr )
263            value = "null";
264         break;
265      }
266      
267      default:
268         break;
269   }
270   
271   return value;
272}
273
274//-----------------------------------------------------------------------------
275
276static void exportFunction( const EngineFunctionInfo* function, SimXMLDocument* xml )
277{
278   if( isExportFiltered( function ) )
279      return;
280      
281   xml->pushNewElement( "EngineFunction" );
282      
283      xml->setAttribute( "name", function->getExportName() );
284      xml->setAttribute( "returnType", getTypeName( function->getReturnType() ) );
285      xml->setAttribute( "symbol", function->getBindingName() );
286      xml->setAttribute( "isCallback", function->isCallout() ? "1" : "0" );
287      xml->setAttribute( "isVariadic", function->getFunctionType()->isVariadic() ? "1" : "0" );
288      xml->setAttribute( "docs", getDocString( function ) );
289      
290      xml->pushNewElement( "arguments" );
291      
292         const U32 numArguments = function->getNumArguments();
293         const U32 numDefaultArguments = ( function->getDefaultArguments() ? function->getDefaultArguments()->mNumDefaultArgs : 0 );
294         const U32 firstDefaultArg = numArguments - numDefaultArguments;
295         
296         Vector< String> argumentNames = parseFunctionArgumentNames( function );
297         const U32 numArgumentNames = argumentNames.size();
298         
299         // Accumulated offset in function argument frame vector.
300         U32 argFrameOffset = 0;
301         
302         for( U32 i = 0; i < numArguments; ++ i )
303         {
304            xml->pushNewElement( "EngineFunctionArgument" );
305            const EngineTypeInfo* type = function->getArgumentType( i );
306            AssertFatal( type != NULL, "exportFunction - Argument cannot have type void!" );
307            
308            String argName;
309            if( i < numArgumentNames )
310               argName = argumentNames[ i ];
311               
312            xml->setAttribute( "name", argName );
313            xml->setAttribute( "type", getTypeName( type ) );
314            
315            if( i >= firstDefaultArg )
316            {
317               String defaultValue = getDefaultArgumentValue( function, type, argFrameOffset );
318               xml->setAttribute( "defaultValue", defaultValue );
319            }
320
321            xml->popElement();
322            
323            if( type->getTypeKind() == EngineTypeKindStruct )
324               argFrameOffset += type->getInstanceSize();
325            else
326               argFrameOffset += type->getValueSize();
327               
328            #ifdef _PACK_BUG_WORKAROUNDS
329            if( argFrameOffset % 4 > 0 )
330               argFrameOffset += 4 - ( argFrameOffset % 4 );
331            #endif
332         }
333         
334      xml->popElement();
335         
336   xml->popElement();
337}
338
339
340//=============================================================================
341//    Types.
342//=============================================================================
343// MARK: ---- Types ----
344
345//-----------------------------------------------------------------------------
346
347static void exportType( const EngineTypeInfo* type, SimXMLDocument* xml )
348{
349   // Don't export anonymous types.
350   if( !type->getTypeName()[ 0 ] )
351      return;
352      
353   if( isExportFiltered( type ) )
354      return;
355      
356   const char* nodeName = NULL;
357   switch( type->getTypeKind() )
358   {
359      case EngineTypeKindPrimitive:
360         nodeName = "EnginePrimitiveType";
361         break;
362         
363      case EngineTypeKindEnum:
364         nodeName = "EngineEnumType";
365         break;
366         
367      case EngineTypeKindBitfield:
368         nodeName = "EngineBitfieldType";
369         break;
370         
371      case EngineTypeKindStruct:
372         nodeName = "EngineStructType";
373         break;
374         
375      case EngineTypeKindClass:
376         nodeName = "EngineClassType";
377         break;
378      
379      default:
380         return;
381   }
382   
383   xml->pushNewElement( nodeName );
384
385      xml->setAttribute( "name", type->getTypeName() );
386      xml->setAttribute( "size", String::ToString( type->getInstanceSize() ) );
387      xml->setAttribute( "isAbstract", type->isAbstract() ? "1" : "0" );
388      xml->setAttribute( "isInstantiable", type->isInstantiable() ? "1" : "0" );
389      xml->setAttribute( "isDisposable", type->isDisposable() ? "1" : "0" );
390      xml->setAttribute( "isSingleton", type->isSingleton() ? "1" : "0" );
391      xml->setAttribute( "docs", getDocString( type ) );
392      
393      if( type->getSuperType() )
394         xml->setAttribute( "superType", getTypeName( type->getSuperType() ) );
395      
396      if( type->getEnumTable() )
397      {
398         xml->pushNewElement( "enums" );
399         
400            const EngineEnumTable& table = *( type->getEnumTable() );
401            const U32 numValues = table.getNumValues();
402            
403            for( U32 i = 0; i < numValues; ++ i )
404            {
405               xml->pushNewElement( "EngineEnum" );
406               
407                  xml->setAttribute( "name", table[ i ].getName() );
408                  xml->setAttribute( "value", String::ToString( table[ i ].getInt() ) );
409                  xml->setAttribute( "docs", table[ i ].getDocString() ? table[ i ].getDocString() : "" );
410                  
411               xml->popElement();
412            }
413            
414         xml->popElement();
415      }
416      else if( type->getFieldTable() )
417      {
418         xml->pushNewElement( "fields" );
419         
420            const EngineFieldTable& table = *( type->getFieldTable() );
421            const U32 numFields = table.getNumFields();
422            
423            for( U32 i = 0; i < numFields; ++ i )
424            {
425               const EngineFieldTable::Field& field = table[ i ];
426               
427               xml->pushNewElement( "EngineField" );
428               
429                  xml->setAttribute( "name", field.getName() );
430                  xml->setAttribute( "type", getTypeName( field.getType() ) );
431                  xml->setAttribute( "offset", String::ToString( field.getOffset() ) );
432                  xml->setAttribute( "indexedSize", String::ToString( field.getNumElements() ) );
433                  xml->setAttribute( "docs", field.getDocString() ? field.getDocString() : "" );
434               
435               xml->popElement();
436            }
437         
438         xml->popElement();
439      }
440      else if( type->getPropertyTable() )
441      {
442         xml->pushNewElement( "properties" );
443         
444            const EnginePropertyTable& table = *( type->getPropertyTable() );
445            const U32 numProperties = table.getNumProperties();
446            U32 groupNestingDepth = 0;
447            
448            for( U32 i = 0; i < numProperties; ++ i )
449            {
450               const EnginePropertyTable::Property& property = table[ i ];
451               
452               if( property.isGroupBegin() )
453               {
454                  groupNestingDepth ++;
455                  xml->pushNewElement( "EnginePropertyGroup" );
456                  
457                     xml->setAttribute( "name", property.getName() );
458                     xml->setAttribute( "indexedSize", String::ToString( property.getNumElements() ) );
459                     xml->setAttribute( "docs", property.getDocString() ? property.getDocString() : "" );
460                     
461                     xml->pushNewElement( "properties" );
462               }
463               else if( property.isGroupEnd() )
464               {
465                  groupNestingDepth --;
466                  xml->popElement();
467                  xml->popElement();
468               }
469               else
470               {
471                  xml->pushNewElement( "EngineProperty" );
472                  
473                     xml->setAttribute( "name", property.getName() );
474                     xml->setAttribute( "indexedSize", String::ToString( property.getNumElements() ) );
475                     xml->setAttribute( "isConstant", property.isConstant() ? "1" : "0" );
476                     xml->setAttribute( "isTransient", property.isTransient() ? "1" : "0" );
477                     xml->setAttribute( "isVisible", property.hideInInspectors() ? "0" : "1" );
478                     xml->setAttribute( "docs", property.getDocString() ? property.getDocString() : "" );
479                  
480                  xml->popElement();
481               }
482            }
483         
484         AssertFatal( !groupNestingDepth, "exportType - Property group nesting mismatch!" );
485         xml->popElement();
486      }      
487      exportScope( type, xml );
488      
489   xml->popElement();
490}
491
492
493//=============================================================================
494//    Scopes.
495//=============================================================================
496// MARK: ---- Scopes ----
497
498//-----------------------------------------------------------------------------
499
500static void exportScope( const EngineExportScope* scope, SimXMLDocument* xml, bool addNode )
501{
502   if( addNode )
503   {
504      if( isExportFiltered( scope ) )
505         return;
506         
507      xml->pushNewElement( "EngineExportScope" );
508      
509         xml->setAttribute( "name", scope->getExportName() );
510         xml->setAttribute( "docs", getDocString( scope ) );
511   }
512
513   // Dump all contained exports.
514   
515   xml->pushNewElement( "exports" );
516   
517      for( const EngineExport* exportInfo = scope->getExports(); exportInfo != NULL; exportInfo = exportInfo->getNextExport() )
518      {
519         switch( exportInfo->getExportKind() )
520         {
521            case EngineExportKindScope:
522               exportScope( static_cast< const EngineExportScope* >( exportInfo ), xml, true );
523               break;
524               
525            case EngineExportKindFunction:
526               exportFunction( static_cast< const EngineFunctionInfo* >( exportInfo ), xml );
527               break;
528               
529            case EngineExportKindType:
530               exportType( static_cast< const EngineTypeInfo* >( exportInfo ), xml );
531               break;
532               
533            default:
534               break;
535         }
536      }
537      
538   xml->popElement();
539   
540   if( addNode )
541      xml->popElement();
542}
543
544//-----------------------------------------------------------------------------
545
546DefineEngineFunction( exportEngineAPIToXML, SimXMLDocument*, (),,
547   "Create a XML document containing a dump of the entire exported engine API.\n\n"
548   "@return A SimXMLDocument containing a dump of the engine's export information or NULL if the operation failed.\n\n"
549   "@ingroup Console" )
550{
551   SimXMLDocument* xml = new SimXMLDocument;
552   xml->registerObject();
553   Sim::getRootGroup()->addObject( xml );
554   xml->addHeader();
555   
556   exportScope( EngineExportScope::getGlobalScope(), xml, true );
557   
558   return xml;
559}
560