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
ADDRESS_TO_TYPE(tp) *( tp*)(addr);
define
PRIMTYPE(tp)             ( < tp >() == type )                                        \
            {                                                                 \
               tp val = (tp);                                  \
                = ( val );                               \
            }

Public Variables

Public Functions

DefineEngineFunction(exportEngineAPIToXML , SimXMLDocument * , () , "Create <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> XML document containing <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</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 href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</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_1a4e4fa7e3399708e0777b5308db01278c">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

ADDRESS_TO_TYPE(tp) *( tp*)(addr);
PRIMTYPE(tp)             ( < tp >() == type )                                        \
            {                                                                 \
               tp val = (tp);                                  \
                = ( val );                               \
            }

Public Variables

const char * sExportFilterList []

Public Functions

DefineEngineFunction(exportEngineAPIToXML , SimXMLDocument * , () , "Create <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> XML document containing <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</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 href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</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_1a4e4fa7e3399708e0777b5308db01278c">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 idx)

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

getDocString(const EngineExport * exportInfo)

getTypeName(const EngineTypeInfo * type)

getValueForType(const EngineTypeInfo * type, void * addr)

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 idx)
 63{
 64   return *(const T*)(defaultArgs->mFirst + defaultArgs->mOffsets[idx]);
 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) || *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//-----------------------------------------------------------------------------
173static String getValueForType(const EngineTypeInfo* type, void* addr)
174{
175   String value;
176#define ADDRESS_TO_TYPE(tp) *(const tp*)(addr);
177
178   switch (type->getTypeKind())
179   {
180   case EngineTypeKindPrimitive:
181   {
182#define PRIMTYPE( tp )                                                        \
183            if( TYPE< tp >() == type )                                        \
184            {                                                                 \
185               tp val = ADDRESS_TO_TYPE(tp);                                  \
186               value = String::ToString( val );                               \
187            }
188
189      PRIMTYPE(bool);
190      PRIMTYPE(S8);
191      PRIMTYPE(U8);
192      PRIMTYPE(S32);
193      PRIMTYPE(U32);
194      PRIMTYPE(F32);
195      PRIMTYPE(F64);
196
197      //TODO: for now we store string literals in ASCII; needs to be sorted out
198      if (TYPE< String >() == type || TYPE< const UTF8* >() == type)
199      {
200         const UTF8* val = *((const UTF8**)(addr));
201         value = val;
202      }
203
204#undef PRIMTYPE
205      break;
206   }
207
208   case EngineTypeKindEnum:
209   {
210      S32 val = ADDRESS_TO_TYPE(S32);
211      AssertFatal(type->getEnumTable(), "engineXMLExport - Enum type without table!");
212
213      const EngineEnumTable& table = *(type->getEnumTable());
214      const U32 numValues = table.getNumValues();
215
216      for (U32 i = 0; i < numValues; ++i)
217         if (table[i].getInt() == val)
218         {
219            value = table[i].getName();
220            break;
221         }
222
223      break;
224   }
225
226   case EngineTypeKindBitfield:
227   {
228      S32 val = ADDRESS_TO_TYPE(S32);
229      AssertFatal(type->getEnumTable(), "engineXMLExport - Bitfield type without table!");
230
231      const EngineEnumTable& table = *(type->getEnumTable());
232      const U32 numValues = table.getNumValues();
233
234      bool isFirst = true;
235      for (U32 i = 0; i < numValues; ++i)
236         if (table[i].getInt() & val)
237         {
238            if (!isFirst)
239               value += '|';
240
241            value = table[i].getName();
242            isFirst = false;
243         }
244
245      break;
246   }
247
248   case EngineTypeKindStruct:
249   {
250      AssertFatal(type->getFieldTable(), "engineXMLExport - Struct type without table!");
251      const EngineFieldTable* fieldTable = type->getFieldTable();
252      U32 numFields = fieldTable->getNumFields();
253
254
255      for (int i = 0; i < numFields; ++i)
256      {
257         const EngineTypeInfo* fieldType = (*fieldTable)[i].getType();
258         U32 fieldOffset = (*fieldTable)[i].getOffset();
259         U32 numElements = (*fieldTable)[i].getNumElements();
260
261         for (int j = 0; j < numElements; ++j)
262         {
263            if (i == 0 && j == 0) {
264               value = getValueForType(fieldType, (void*)((size_t)addr + fieldOffset));
265            }
266            else {
267               value += " " + getValueForType(fieldType, (void*)((size_t)addr + (size_t)fieldOffset * ((size_t)j * fieldType->getInstanceSize())));
268            }
269         }
270      }
271
272      break;
273   }
274
275   case EngineTypeKindClass:
276   case EngineTypeKindFunction:
277   {
278      // For these two kinds, we support "null" as the only valid
279      // default value.
280
281      const void* ptr = ADDRESS_TO_TYPE(void*);
282      if (!ptr)
283         value = "null";
284      break;
285   }
286
287   default:
288      break;
289   }
290
291#undef ADDRESS_TO_TYPE
292   return value;
293}
294
295//-----------------------------------------------------------------------------
296
297static String getDefaultArgumentValue(const EngineFunctionInfo* function, const EngineTypeInfo* type, U32 idx)
298{
299   const EngineFunctionDefaultArguments* defaultArgs = function->getDefaultArguments();
300   return getValueForType(type, (void*)(defaultArgs->mFirst + defaultArgs->mOffsets[idx]));
301}
302
303//-----------------------------------------------------------------------------
304
305static void exportFunction(const EngineFunctionInfo* function, SimXMLDocument* xml)
306{
307   if (isExportFiltered(function))
308      return;
309
310   xml->pushNewElement("EngineFunction");
311
312   xml->setAttribute("name", function->getExportName());
313   xml->setAttribute("returnType", getTypeName(function->getReturnType()));
314   xml->setAttribute("symbol", function->getBindingName());
315   xml->setAttribute("isCallback", function->isCallout() ? "1" : "0");
316   xml->setAttribute("isVariadic", function->getFunctionType()->isVariadic() ? "1" : "0");
317   xml->setAttribute("docs", getDocString(function));
318
319   xml->pushNewElement("arguments");
320
321   const U32 numArguments = function->getNumArguments();
322   const U32 numDefaultArguments = (function->getDefaultArguments() ? function->getDefaultArguments()->mNumDefaultArgs : 0);
323   const U32 firstDefaultArg = numArguments - numDefaultArguments;
324
325   Vector< String> argumentNames = parseFunctionArgumentNames(function);
326   const U32 numArgumentNames = argumentNames.size();
327
328   for (U32 i = 0; i < numArguments; ++i)
329   {
330      xml->pushNewElement("EngineFunctionArgument");
331      const EngineTypeInfo* type = function->getArgumentType(i);
332      AssertFatal(type != NULL, "exportFunction - Argument cannot have type void!");
333
334      String argName;
335      if (i < numArgumentNames)
336         argName = argumentNames[i];
337
338      xml->setAttribute("name", argName);
339      xml->setAttribute("type", getTypeName(type));
340
341      if (i >= firstDefaultArg)
342      {
343         String defaultValue = getDefaultArgumentValue(function, type, i);
344         xml->setAttribute("defaultValue", defaultValue);
345      }
346
347      // A bit hacky, default arguments have all offsets.
348      if (function->getDefaultArguments() != NULL)
349      {
350         xml->setAttribute("offset", String::ToString(function->getDefaultArguments()->mOffsets[i]));
351      }
352
353      xml->popElement();
354   }
355
356   xml->popElement();
357
358   xml->popElement();
359}
360
361
362//=============================================================================
363//    Types.
364//=============================================================================
365// MARK: ---- Types ----
366
367//-----------------------------------------------------------------------------
368
369static void exportType(const EngineTypeInfo* type, SimXMLDocument* xml)
370{
371   // Don't export anonymous types.
372   if (!type->getTypeName()[0])
373      return;
374
375   if (isExportFiltered(type))
376      return;
377
378   const char* nodeName = NULL;
379   switch (type->getTypeKind())
380   {
381   case EngineTypeKindPrimitive:
382      nodeName = "EnginePrimitiveType";
383      break;
384
385   case EngineTypeKindEnum:
386      nodeName = "EngineEnumType";
387      break;
388
389   case EngineTypeKindBitfield:
390      nodeName = "EngineBitfieldType";
391      break;
392
393   case EngineTypeKindStruct:
394      nodeName = "EngineStructType";
395      break;
396
397   case EngineTypeKindClass:
398      nodeName = "EngineClassType";
399      break;
400
401   default:
402      return;
403   }
404
405   xml->pushNewElement(nodeName);
406
407   xml->setAttribute("name", type->getTypeName());
408   xml->setAttribute("size", String::ToString(type->getInstanceSize()));
409   xml->setAttribute("isAbstract", type->isAbstract() ? "1" : "0");
410   xml->setAttribute("isInstantiable", type->isInstantiable() ? "1" : "0");
411   xml->setAttribute("isDisposable", type->isDisposable() ? "1" : "0");
412   xml->setAttribute("isSingleton", type->isSingleton() ? "1" : "0");
413   xml->setAttribute("docs", getDocString(type));
414
415   if (type->getSuperType())
416      xml->setAttribute("superType", getTypeName(type->getSuperType()));
417
418   if (type->getEnumTable())
419   {
420      xml->pushNewElement("enums");
421
422      const EngineEnumTable& table = *(type->getEnumTable());
423      const U32 numValues = table.getNumValues();
424
425      for (U32 i = 0; i < numValues; ++i)
426      {
427         xml->pushNewElement("EngineEnum");
428
429         xml->setAttribute("name", table[i].getName());
430         xml->setAttribute("value", String::ToString(table[i].getInt()));
431         xml->setAttribute("docs", table[i].getDocString() ? table[i].getDocString() : "");
432
433         xml->popElement();
434      }
435
436      xml->popElement();
437   }
438   else if (type->getFieldTable())
439   {
440      xml->pushNewElement("fields");
441
442      const EngineFieldTable& table = *(type->getFieldTable());
443      const U32 numFields = table.getNumFields();
444
445      for (U32 i = 0; i < numFields; ++i)
446      {
447         const EngineFieldTable::Field& field = table[i];
448
449         xml->pushNewElement("EngineField");
450
451         xml->setAttribute("name", field.getName());
452         xml->setAttribute("type", getTypeName(field.getType()));
453         xml->setAttribute("offset", String::ToString(field.getOffset()));
454         xml->setAttribute("indexedSize", String::ToString(field.getNumElements()));
455         xml->setAttribute("docs", field.getDocString() ? field.getDocString() : "");
456
457         xml->popElement();
458      }
459
460      xml->popElement();
461   }
462   else if (type->getPropertyTable())
463   {
464      xml->pushNewElement("properties");
465
466      const EnginePropertyTable& table = *(type->getPropertyTable());
467      const U32 numProperties = table.getNumProperties();
468      U32 groupNestingDepth = 0;
469
470      for (U32 i = 0; i < numProperties; ++i)
471      {
472         const EnginePropertyTable::Property& property = table[i];
473
474         if (property.isGroupBegin())
475         {
476            groupNestingDepth++;
477            xml->pushNewElement("EnginePropertyGroup");
478
479            xml->setAttribute("name", property.getName());
480            xml->setAttribute("indexedSize", String::ToString(property.getNumElements()));
481            xml->setAttribute("docs", property.getDocString() ? property.getDocString() : "");
482
483            xml->pushNewElement("properties");
484         }
485         else if (property.isGroupEnd())
486         {
487            groupNestingDepth--;
488            xml->popElement();
489            xml->popElement();
490         }
491         else
492         {
493            if (property.getType() == AbstractClassRep::StartArrayFieldType
494               || property.getType() == AbstractClassRep::EndArrayFieldType) {
495               continue;
496            }
497            xml->pushNewElement("EngineProperty");
498
499            xml->setAttribute("name", property.getName());
500            xml->setAttribute("indexedSize", String::ToString(property.getNumElements()));
501            xml->setAttribute("isConstant", property.isConstant() ? "1" : "0");
502            xml->setAttribute("isTransient", property.isTransient() ? "1" : "0");
503            xml->setAttribute("isVisible", property.hideInInspectors() ? "0" : "1");
504            xml->setAttribute("docs", property.getDocString() ? property.getDocString() : "");
505
506
507            const bool isDeprecated = (property.getType() == AbstractClassRep::DeprecatedFieldType);
508
509            if (isDeprecated)
510            {
511               xml->setAttribute("type", "deprecated");
512            }
513            else
514            {
515               ConsoleBaseType *cbt = ConsoleBaseType::getType(property.getType());
516               if (cbt != NULL)
517               {
518                  if (cbt->getTypeInfo() != NULL) {
519                     xml->setAttribute("type", cbt->getTypeInfo()->getTypeName());
520                  }
521                  else {
522                     xml->setAttribute("type", cbt->getTypeClassName());
523                  }
524               }
525               else
526               {
527                  xml->setAttribute("type", "unknown");
528               }
529            }
530
531            xml->popElement();
532         }
533      }
534
535      AssertFatal(!groupNestingDepth, "exportType - Property group nesting mismatch!");
536      xml->popElement();
537   }
538   exportScope(type, xml);
539
540   xml->popElement();
541}
542
543
544//=============================================================================
545//    Scopes.
546//=============================================================================
547// MARK: ---- Scopes ----
548
549//-----------------------------------------------------------------------------
550
551static void exportScope(const EngineExportScope* scope, SimXMLDocument* xml, bool addNode)
552{
553   if (addNode)
554   {
555      if (isExportFiltered(scope))
556         return;
557
558      xml->pushNewElement("EngineExportScope");
559
560      xml->setAttribute("name", scope->getExportName());
561      xml->setAttribute("docs", getDocString(scope));
562   }
563
564   // Dump all contained exports.
565
566   xml->pushNewElement("exports");
567
568   for (const EngineExport* exportInfo = scope->getExports(); exportInfo != NULL; exportInfo = exportInfo->getNextExport())
569   {
570      switch (exportInfo->getExportKind())
571      {
572      case EngineExportKindScope:
573         exportScope(static_cast< const EngineExportScope* >(exportInfo), xml, true);
574         break;
575
576      case EngineExportKindFunction:
577         exportFunction(static_cast< const EngineFunctionInfo* >(exportInfo), xml);
578         break;
579
580      case EngineExportKindType:
581         exportType(static_cast< const EngineTypeInfo* >(exportInfo), xml);
582         break;
583
584      default:
585         AssertFatal(true, "Unknown EngineExportKind: " + exportInfo->getExportKind());
586         break;
587      }
588   }
589
590   xml->popElement();
591
592   if (addNode)
593      xml->popElement();
594}
595
596//-----------------------------------------------------------------------------
597
598DefineEngineFunction(exportEngineAPIToXML, SimXMLDocument*, (), ,
599   "Create a XML document containing a dump of the entire exported engine API.\n\n"
600   "@return A SimXMLDocument containing a dump of the engine's export information or NULL if the operation failed.\n\n"
601   "@ingroup Console")
602{
603   SimXMLDocument* xml = new SimXMLDocument;
604   xml->registerObject();
605   Sim::getRootGroup()->addObject(xml);
606   xml->addHeader();
607
608   exportScope(EngineExportScope::getGlobalScope(), xml, true);
609
610   return xml;
611}
612