mummy  1.0.3
MummyCsharpExportLayerGenerator.cxx
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 //
3 // $Id: MummyCsharpExportLayerGenerator.cxx 2 2007-12-17 18:15:56Z david.cole $
4 //
5 // $Author: david.cole $
6 // $Date: 2007-12-17 13:15:56 -0500 (Mon, 17 Dec 2007) $
7 // $Revision: 2 $
8 //
9 // Copyright (C) 2006-2007 Kitware, Inc.
10 //
11 //----------------------------------------------------------------------------
12 
14 #include "MummyCsharpGenerator.h"
15 #include "MummyLog.h"
16 #include "MummySettings.h"
17 
18 #include "cableClass.h"
19 #include "cableClassType.h"
20 #include "cableConstructor.h"
21 #include "cableFunctionType.h"
22 #include "cableMethod.h"
23 #include "cablePointerType.h"
24 #include "cableReferenceType.h"
25 #include "cxxCvQualifiedType.h"
26 #include "cxxFunctionType.h"
27 #include "cxxPointerType.h"
28 #include "cxxType.h"
29 
30 #include "gxsys/stl/set"
31 #include "gxsys/SystemTools.hxx"
32 
33 
34 //----------------------------------------------------------------------------
36 {
37  this->CsharpGenerator = 0;
38 }
39 
40 
41 //----------------------------------------------------------------------------
43 {
44 }
45 
46 
47 //----------------------------------------------------------------------------
49 {
50  this->EmitClassForExportLayer(*GetStream(), GetTargetClass());
51  return false;
52 }
53 
54 
55 //----------------------------------------------------------------------------
57 {
58  return this->CsharpGenerator;
59 }
60 
61 
62 //----------------------------------------------------------------------------
64 {
65  this->CsharpGenerator = generator;
66 }
67 
68 
69 //----------------------------------------------------------------------------
70 //bool MummyCsharpExportLayerGenerator::FundamentalTypeIsWrappable(const cable::Type* t)
71 //{
72 // return this->GetCsharpGenerator()->FundamentalTypeIsWrappable(t);
73 //}
74 
75 
76 //----------------------------------------------------------------------------
77 //bool MummyCsharpExportLayerGenerator::TypeIsWrappable(const cable::Type* t)
78 //{
79 // return this->GetCsharpGenerator()->TypeIsWrappable(t);
80 //}
81 
82 
83 //----------------------------------------------------------------------------
84 //bool MummyCsharpExportLayerGenerator::FunctionTypeIsWrappable(const cable::FunctionType* ft)
85 //{
86 // return this->GetCsharpGenerator()->FunctionTypeIsWrappable(ft);
87 //}
88 
89 
90 //----------------------------------------------------------------------------
91 //bool MummyCsharpExportLayerGenerator::MethodIsWrappable(const cable::Method* m, const cable::Context::Access& access)
92 //{
93 // return this->GetCsharpGenerator()->MethodIsWrappable(m, access);
94 //}
95 
96 
97 //----------------------------------------------------------------------------
98 //bool MummyCsharpExportLayerGenerator::ClassIsWrappable(const cable::Class* c)
99 //{
100 // return this->GetCsharpGenerator()->ClassIsWrappable(c);
101 //}
102 
103 
104 //----------------------------------------------------------------------------
105 const char *MummyCsharpExportLayerGenerator::GetArgName(cable::FunctionType *ftype, unsigned int i)
106 {
107  return this->GetCsharpGenerator()->GetArgName(ftype, i);
108 }
109 
110 
111 //----------------------------------------------------------------------------
112 gxsys_stl::string MummyCsharpExportLayerGenerator::GetExportLayerFunctionName(const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname)
113 {
114  return this->GetCsharpGenerator()->GetExportLayerFunctionName(c, m, mname);
115 }
116 
117 
118 //----------------------------------------------------------------------------
119 gxsys_stl::string GetExportLayerActualType(cable::Type *t, bool stripConst)
120 {
121  gxsys_stl::string s(t->GetCxxType().GetName());
122 
123  if (stripConst)
124  {
125  s = t->GetCxxType().GetType()->GenerateName("", false, false);
126  }
127 
128  return s;
129 }
130 
131 
132 //----------------------------------------------------------------------------
133 gxsys_stl::string GetExportLayerMappedType(cable::Type *t, bool stripConst)
134 {
135  gxsys_stl::string s;
136 
137  if (HasMapToType(t))
138  {
139  // 't' should be either a class or a reference to a class...
140  //
141  cable::Class* c = 0;
142 
143  if (cable::Type::ClassTypeId == t->GetTypeId())
144  {
145  c = cable::ClassType::SafeDownCast(t)->GetClass();
146  }
147  else if (cable::Type::ReferenceTypeId == t->GetTypeId())
148  {
149  c = cable::ClassType::SafeDownCast(
150  cable::ReferenceType::SafeDownCast(t)->GetTarget())->GetClass();
151  }
152 
153  if (c)
154  {
155  s = ExtractMapToType(c);
156  }
157 
158  // Abstract "string" type translates to "const char*" in the export layer:
159  //
160  if (s == "string")
161  {
162  if (stripConst)
163  {
164  s = "char*";
165  }
166  else
167  {
168  s = "const char*";
169  }
170  }
171  else
172  {
173  s = "ERROR_unknown_mapped_to_type_or_null_class_type_in_the_export_layer";
174  LogError(me_InternalError, << s.c_str());
175  }
176  }
177  else
178  {
179  s = GetExportLayerActualType(t, stripConst);
180  }
181 
182  return s;
183 }
184 
185 
186 //----------------------------------------------------------------------------
187 gxsys_stl::string MummyCsharpExportLayerGenerator::GetArgTypeAndNameString(cable::Type *argType, const char *name, bool stripConst)
188 {
189  gxsys_stl::string s;
190 
191  if ((argType->GetTypeId() == cable::Type::PointerTypeId) &&
192  (cable::PointerType::SafeDownCast(argType)->GetTarget()->GetTypeId() == cable::Type::FunctionTypeId)
193  )
194  {
195  if (EquivalentTypedefNameExists(this->GetTargetClass(), cable::FunctionType::SafeDownCast(cable::PointerType::SafeDownCast(argType)->GetTarget()), s))
196  {
197  s = gxsys_stl::string(GetFullyQualifiedNameForCPlusPlus(this->GetTargetClass())) + "::" + s;
198  }
199  else
200  {
201  s = "ERROR - cannot generate argTypeAndName string for function pointer - add a typedef for the function pointer...";
202  LogError(me_InternalError, << s.c_str());
203  }
204  }
205  else
206  {
207  s = GetExportLayerMappedType(argType, stripConst);
208  }
209 
210  if (name)
211  {
212  s += " ";
213  s += name;
214  }
215 
216  return s;
217 }
218 
219 
220 //----------------------------------------------------------------------------
221 void MummyCsharpExportLayerGenerator::EmitClassMethodDeclarationForExportLayer(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, bool emitExceptionParams)
222 {
223  gxsys_stl::string cname(GetFullyQualifiedNameForCPlusPlus(c));
224  gxsys_stl::string s;
225  cable::FunctionType *ft = m->GetFunctionType();
226  unsigned int cArgs = ft->GetNumberOfArguments();
227  unsigned int cArgsEmitted = 0;
228  unsigned int i = 0;
229  cable::Type *retType = ft->GetReturns();
230  cable::Type *argType = 0;
231  cable::Class* cByRefClass = 0;
232 
233  // Extern "C":
234  Emit(os, "extern \"C\" ");
235 
236  // Export declspec:
237  Emit(os, "MUMMY_DLL_EXPORT\n");
238 
239  // Special case "new" and "delete" -- the rest are strictly according to the
240  // method definition as given by 'm'...
241  //
242  if (mname == "new")
243  {
244  // Return type:
245  Emit(os, cname.c_str());
246  Emit(os, "* ");
247 
248  // Exported function name:
249  Emit(os, GetExportLayerFunctionName(c, m, mname).c_str());
250 
251  Emit(os, "(unsigned int* mteStatus, unsigned int* mteIndex, unsigned int* rawRefCount");
252  cArgsEmitted += 3;
253 
254  if (emitExceptionParams)
255  {
256  Emit(os, ", unsigned int* mteExceptionIndex, void** clonedException");
257  cArgsEmitted += 2;
258  }
259 
260  Emit(os, ")\n");
261  }
262  else if (mname == "delete")
263  {
264  // Return type:
265  Emit(os, "void");
266  Emit(os, " ");
267 
268  // Exported function name:
269  Emit(os, GetExportLayerFunctionName(c, m, mname).c_str());
270 
271  Emit(os, "(");
272  Emit(os, cname.c_str());
273  Emit(os, "* pThis");
274  cArgsEmitted += 1;
275 
276  if (emitExceptionParams)
277  {
278  Emit(os, ", unsigned int* mteExceptionIndex, void** clonedException");
279  cArgsEmitted += 2;
280  }
281 
282  Emit(os, ")\n");
283  }
284  else
285  {
286  // Return type:
287  Emit(os, GetArgTypeAndNameString(retType, 0, false).c_str());
288  Emit(os, " ");
289 
290  // Exported function name:
291  Emit(os, GetExportLayerFunctionName(c, m, mname).c_str());
292 
293  // Open args:
294  Emit(os, "(");
295 
296  // The "this" arg:
297  if (!m->GetStatic())
298  {
299  Emit(os, cname.c_str());
300  Emit(os, "* pThis");
301  cArgsEmitted += 1;
302 
303  if (cArgs!=0)
304  {
305  Emit(os, ", ");
306  }
307  }
308 
309  // The real args:
310  for (i= 0; i<cArgs; ++i)
311  {
312  argType = ft->GetArgument(i);
313 
314  // Utility classes get marshalled as copies across the boundary from C#
315  // even if in C++ they are & (byref) arguments... So they need to be
316  // declared as just plain old stack-based by value arguments here.
317  //
318  cByRefClass = 0;
319 
320  if (cable::Type::ReferenceTypeId == argType->GetTypeId())
321  {
322  cable::ClassType* classType = cable::ClassType::SafeDownCast(
323  cable::ReferenceType::SafeDownCast(argType)->GetTarget());
324  if (classType)
325  {
326  cByRefClass = classType->GetClass();
327  }
328  }
329 
330  if (cByRefClass && IsUtilityClass(cByRefClass))
331  {
332  Emit(os, GetFullyQualifiedNameForCPlusPlus(cByRefClass).c_str());
333  Emit(os, " ");
334  Emit(os, GetArgName(ft, i));
335  }
336  else
337  {
338  Emit(os, GetArgTypeAndNameString(argType, GetArgName(ft, i), false).c_str());
339  }
340 
341  cArgsEmitted += 1;
342 
343  if (i<cArgs-1)
344  {
345  Emit(os, ", ");
346  }
347  }
348 
349  // Add "generated args" to method signatures that return object pointers:
350  //
351  if (!HasMapToType(retType) && IsObjectPointer(retType))
352  {
353  if (cArgsEmitted)
354  {
355  Emit(os, ", ");
356  }
357 
358  Emit(os, "unsigned int* mteStatus, unsigned int* mteIndex, unsigned int* rawRefCount");
359  cArgsEmitted += 3;
360  }
361 
362  if (emitExceptionParams)
363  {
364  if (cArgsEmitted)
365  {
366  Emit(os, ", ");
367  }
368 
369  Emit(os, "unsigned int* mteExceptionIndex, void** clonedException");
370  cArgsEmitted += 2;
371  }
372 
373  // Close args:
374  Emit(os, ")\n");
375  }
376 }
377 
378 
379 //----------------------------------------------------------------------------
380 void MummyCsharpExportLayerGenerator::EmitSpecialHandlingForObjectPointerReturns(gxsys_ios::ostream &os, const gxsys_stl::string& cname, const cable::Method *, const gxsys_stl::string&, const unsigned int indent)
381 {
383  if (!this->GetSettings()->FindClassWrappingSettings(cname.c_str(), &cws))
384  {
386  << "error: no ClassWrappingSettings for class " << cname.c_str());
387  }
388 
389  EmitIndent(os, indent);
390  Emit(os, "if (0 != rv)\n");
391  EmitIndent(os, indent+1);
392  Emit(os, "{\n");
393 
394  gxsys_stl::string registerMethod = cws.registerMethod;
395  gxsys_stl::string registerBaseClass = cws.registerBaseClass;
396  gxsys_stl::string getRefCountMethod = cws.getRefCountMethod;
397  gxsys_stl::string getMummyTypeEntryMethod = cws.getMummyTypeEntryMethod;
398  gxsys_stl::string setMummyTypeEntryMethod = cws.setMummyTypeEntryMethod;
399 
400  if (!registerMethod.empty())
401  {
402  EmitIndent(os, indent+1);
403  Emit(os, registerBaseClass.c_str());
404  Emit(os, "* ro = (");
405  Emit(os, registerBaseClass.c_str());
406  Emit(os, "*) (void*) rv;\n");
407  }
408 
409 
410  if (!registerMethod.empty() && !getMummyTypeEntryMethod.empty())
411  {
412  // If object supports MummyTypeEntry caching:
413  //
414  EmitIndent(os, indent+1);
415  Emit(os, "Kitware::mummy::TypeEntry* entry = ro->");
416  Emit(os, getMummyTypeEntryMethod.c_str());
417  Emit(os, "();\n");
418  EmitIndent(os, indent+1);
419  Emit(os, "if (!entry)\n");
420  EmitIndent(os, indent+2);
421  Emit(os, "{\n");
422  EmitIndent(os, indent+2);
423  Emit(os, "entry = Kitware::mummy::Runtime::GetTypeEntry((void*) rv, typeid(*ro).name());\n");
424  EmitIndent(os, indent+2);
425  Emit(os, "ro->");
426  Emit(os, setMummyTypeEntryMethod.c_str());
427  Emit(os, "(entry);\n");
428  EmitIndent(os, indent+2);
429  Emit(os, "*mteStatus = 1;\n");
430  EmitIndent(os, indent+2);
431  Emit(os, "}\n");
432  EmitIndent(os, indent+1);
433  Emit(os, "else\n");
434  EmitIndent(os, indent+2);
435  Emit(os, "{\n");
436  EmitIndent(os, indent+2);
437  Emit(os, "*mteStatus = 2;\n");
438  EmitIndent(os, indent+2);
439  Emit(os, "}\n");
440  }
441  else
442  {
443  // ...otherwise always call Runtime::GetTypeEntry:
444  //
445  EmitIndent(os, indent+1);
446  Emit(os, "Kitware::mummy::TypeEntry* entry = Kitware::mummy::Runtime::GetTypeEntry(\n");
447 
448  EmitIndent(os, indent+2);
449  Emit(os, "(void*) rv, typeid(*");
450  if (!registerMethod.empty())
451  {
452  // Prefer "ro" (if we have it) to "rv" simply because
453  // typeid(*obj).name() is really really stupid.
454  //
455  Emit(os, "ro");
456  }
457  else
458  {
459  Emit(os, "rv");
460  }
461  Emit(os, ").name());\n");
462 
463  EmitIndent(os, indent+1);
464  Emit(os, "*mteStatus = 0;\n");
465  }
466 
467  // So here we always have an entry:
468  //
469  EmitIndent(os, indent+1);
470  Emit(os, "*mteIndex = entry->GetIndex();\n");
471 
472  if (!registerMethod.empty() && !getRefCountMethod.empty())
473  {
474  EmitIndent(os, indent+1);
475  Emit(os, "*rawRefCount = (unsigned int) ro->");
476  Emit(os, getRefCountMethod.c_str());
477  Emit(os, ";\n");
478  }
479  else
480  {
481  EmitIndent(os, indent+1);
482  Emit(os, "*rawRefCount = (unsigned int) -86;\n");
483  }
484 
485  EmitIndent(os, indent+1);
486  Emit(os, "}\n");
487 }
488 
489 
490 //----------------------------------------------------------------------------
491 void MummyCsharpExportLayerGenerator::EmitClassMethodForExportLayer(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname)
492 {
493  gxsys_stl::string cname(GetFullyQualifiedNameForCPlusPlus(c));
494  cable::FunctionType *ft = m->GetFunctionType();
495  unsigned int cArgs = ft->GetNumberOfArguments();
496  unsigned int i = 0;
497  unsigned int indent = 1;
498  cable::Type *retType = ft->GetReturns();
499  cable::PointerType::Pointer fakeRetType;
500  bool voidReturn = false;
501  bool mappedReturnType = false;
502  bool emitExceptionBlock = false;
503  gxsys_stl::string rvTypeStr;
504  bool needsInit = false;
505  gxsys_stl::string initExpression;
506 
508  if (!this->GetSettings()->FindClassWrappingSettings(GetFullyQualifiedNameForCPlusPlus(c).c_str(), &cws))
509  {
511  << "error: no ClassWrappingSettings for class " << GetFullyQualifiedNameForCPlusPlus(c).c_str());
512  }
513 
514  emitExceptionBlock = !cws.exceptionBaseClass.empty();
515 
516  // If mname is "new" fake retType:
517  //
518  if (mname == "new")
519  {
520  fakeRetType = cable::PointerType::New();
521  fakeRetType->SetTarget(c->GetClassType());
522  fakeRetType->CreateCxxType(this->GetSourceRepresentation()->GetTypeSystem());
523  retType = fakeRetType;
524  }
525 
526  // Is there a return value? Do we need to map/transform it to a different type?
527  //
528  if (IsVoid(retType))
529  {
530  voidReturn = true;
531  }
532  else if (HasMapToType(retType))
533  {
534  mappedReturnType = true;
535  }
536 
537  // Declaration:
538  EmitClassMethodDeclarationForExportLayer(os, c, m, mname, emitExceptionBlock);
539 
540  // Open body:
541  Emit(os, "{\n");
542 
543  // Declare return value "rv":
544  if (!voidReturn)
545  {
546  if (cable::Type::ReferenceTypeId == retType->GetTypeId())
547  {
548  rvTypeStr = gxsys_stl::string("ref<") + GetArgTypeAndNameString(
549  cable::ReferenceType::SafeDownCast(retType)->GetTarget(), 0, false) + ">";
550  needsInit = false;
551  }
552  else if (mappedReturnType)
553  {
554  rvTypeStr = GetArgTypeAndNameString(retType, 0, true);
555  needsInit = true;
556 
557  initExpression = "cast";
558  // david.cole::fix -- this works for the only mapped type we currently
559  // support ("string" / "const char*") -- it needs to be generalized
560  // to generate correct code if we ever introduce more mapped types...
561  }
562  else
563  {
564  rvTypeStr = GetArgTypeAndNameString(retType, 0, true);
565  needsInit = true;
566 
567  initExpression = GetCPlusPlusZeroInitializerExpression(retType);
568  }
569 
570  EmitIndent(os);
571  Emit(os, rvTypeStr.c_str());
572  Emit(os, " rv");
573 
574  if (needsInit)
575  {
576  if (initExpression == "memset")
577  {
578  Emit(os, ";\n");
579  EmitIndent(os);
580  Emit(os, "memset(&rv, 0, sizeof(rv))");
581  }
582  else if (initExpression == "cast")
583  {
584  Emit(os, " = (");
585  Emit(os, rvTypeStr.c_str());
586  Emit(os, ") 0");
587  }
588  else
589  {
590  Emit(os, " = ");
591  Emit(os, initExpression.c_str());
592  }
593  }
594 
595  Emit(os, ";");
596  Emit(os, "\n");
597  Emit(os, "\n");
598  }
599 
600  // Open exception try block:
601  if (emitExceptionBlock)
602  {
603  EmitIndent(os);
604  Emit(os, "try\n");
605  EmitIndent(os);
606  Emit(os, "{\n");
607 
608  indent++;
609  }
610 
611  // Delegate the call to the real underlying object:
612  EmitIndent(os, indent);
613 
614  if (!voidReturn)
615  {
616  if (mappedReturnType)
617  {
618  Emit(os, GetExportLayerActualType(retType, true).c_str());
619  Emit(os, " rvmi = ");
620  }
621  else
622  {
623  Emit(os, "rv = ");
624  }
625  }
626 
627  // Special case "new" and "delete" -- the rest are strictly according to the
628  // method definition as given by 'm'...
629  //
630  if (mname == "new")
631  {
632  Emit(os, "new ");
633  Emit(os, cname.c_str());
634  Emit(os, ";");
635  Emit(os, "\n");
636  }
637  else if (mname == "delete")
638  {
639  Emit(os, "delete pThis;");
640  Emit(os, "\n");
641  }
642  else
643  {
644  if (!m->GetStatic())
645  {
646  Emit(os, "pThis->");
647  }
648  else
649  {
650  Emit(os, cname.c_str());
651  Emit(os, "::");
652  }
653 
654  Emit(os, mname.c_str());
655  Emit(os, "(");
656  for (i= 0; i<cArgs; ++i)
657  {
658  Emit(os, GetArgName(ft, i));
659 
660  if (i<cArgs-1)
661  {
662  Emit(os, ", ");
663  }
664  }
665  Emit(os, ");");
666  Emit(os, "\n");
667  }
668 
669 
670  // Map return type from "rvmi" to "rv":
671  //
672  if (mappedReturnType)
673  {
674  gxsys_stl::string map_to_type = GetMapToType(retType);
675  gxsys_stl::string mapping_method = GetStringMethod(retType);
676 
677  Emit(os, "\n");
678 
679  EmitIndent(os, indent);
680  Emit(os, GetExportLayerMappedType(retType, false).c_str());
681  Emit(os, " rvm = rvmi.");
682  Emit(os, mapping_method.c_str());
683  Emit(os, "();\n");
684 
685  if (map_to_type == "string")
686  {
687  EmitIndent(os, indent);
688  Emit(os, "size_t n = 0;\n");
689  Emit(os, "\n");
690  EmitIndent(os, indent);
691  Emit(os, "if (rvm)\n");
692  EmitIndent(os, indent+1);
693  Emit(os, "{\n");
694  EmitIndent(os, indent+1);
695  Emit(os, "n = strlen(rvm);\n");
696  EmitIndent(os, indent+1);
697  Emit(os, "}\n");
698  Emit(os, "\n");
699  EmitIndent(os, indent);
700  Emit(os, "rv = (char*) MUMMY_STRING_ALLOC(n+1);\n");
701  EmitIndent(os, indent);
702  Emit(os, "if (rv)\n");
703  EmitIndent(os, indent+1);
704  Emit(os, "{\n");
705  EmitIndent(os, indent+1);
706  Emit(os, "strncpy(rv, rvm, n);\n");
707  EmitIndent(os, indent+1);
708  Emit(os, "rv[n] = 0;\n");
709  EmitIndent(os, indent+1);
710  Emit(os, "}\n");
711  Emit(os, "\n");
712  }
713  else
714  {
715  LogFileLineErrorMsg(m->GetFile(), m->GetLine(), me_UnknownMapToType,
716  << "Unknown iwhMapToType for return type of method '" << m->GetName() << "'");
717  }
718  }
719  else if (IsObjectPointer(retType))
720  {
721  const cable::Class* cRetType = cable::ClassType::SafeDownCast(
722  cable::PointerType::SafeDownCast(retType)->GetTarget()
723  )->GetClass();
724 
726  }
727 
728  // Close exception try block:
729  if (emitExceptionBlock)
730  {
731  EmitIndent(os);
732  Emit(os, "}\n");
733  EmitIndent(os);
734  Emit(os, "catch(");
735  Emit(os, cws.exceptionBaseClass.c_str());
736  Emit(os, "& mel_exc)\n");
737  EmitIndent(os);
738  Emit(os, "{\n");
739 
740  EmitIndent(os, 2);
741  Emit(os, cws.exceptionBaseClass.c_str());
742  Emit(os, "* mel_exc_clone = mel_exc.");
743  Emit(os, cws.exceptionCloneMethod.c_str());
744  Emit(os, "();\n");
745 
746  EmitIndent(os, 2);
747  Emit(os, "Kitware::mummy::TypeEntry* entry = Kitware::mummy::Runtime::GetTypeEntry(\n");
748 
749  EmitIndent(os, 3);
750  Emit(os, "(void*) mel_exc_clone, typeid(*mel_exc_clone).name());\n");
751 
752  EmitIndent(os, 2);
753  Emit(os, "*clonedException = mel_exc_clone;\n");
754 
755  EmitIndent(os, 2);
756  Emit(os, "*mteExceptionIndex = entry->GetIndex();\n");
757 
758  EmitIndent(os);
759  Emit(os, "}\n");
760  }
761 
762  // Return statement:
763  if (!voidReturn)
764  {
765  Emit(os, "\n");
766  EmitIndent(os);
767  Emit(os, "return rv;\n");
768  }
769 
770  // Close body:
771  Emit(os, "}\n");
772 }
773 
774 
775 //----------------------------------------------------------------------------
776 void MummyCsharpExportLayerGenerator::EmitClassForExportLayer(gxsys_ios::ostream &os, const cable::Class *c)
777 {
778  gxsys_stl::string header(c->GetFile());
779 
782  {
784  << "error: no ClassWrappingSettings for class " << GetFullyQualifiedNameForCPlusPlus(c).c_str());
785  }
786 
787  // Emit code:
788  //
789  EmitMummyVersionComments(os, "//");
790 
791  // If the class maps directly to a builtin type, then DO NOT emit any code.
792  //
793  gxsys_stl::string mapToType = ExtractMapToType(c);
794  if (mapToType != "")
795  {
796  Emit(os, "\n");
797  Emit(os, "//----------------------------------------------------------------------------\n");
798  Emit(os, "// Unmanaged class '");
799  Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str());
800  Emit(os, "' maps directly to type '");
801  Emit(os, mapToType.c_str());
802  Emit(os, "'.\n");
803  Emit(os, "// No code generated for '");
804  Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str());
805  Emit(os, "'...\n");
806 
807  LogVerboseInfo(<< "Skipping code generation because class maps directly to native type.");
808 
809  return;
810  }
811 
812  Emit(os, "\n");
813  Emit(os, "//----------------------------------------------------------------------------\n");
814  Emit(os, "// You can use this symbol in your header files if there are bits of your\n");
815  Emit(os, "// code that should be conditionally compiled in this export layer.\n");
816  Emit(os, "//\n");
817  Emit(os, "#define MUMMY_EXPORT_LAYER_CXX\n");
818  Emit(os, "\n");
819  Emit(os, "//----------------------------------------------------------------------------\n");
820  Emit(os, "// Do not emit the silly C4996 warning for strncpy use:\n");
821  Emit(os, "//\n");
822  Emit(os, "#ifndef _CRT_SECURE_NO_DEPRECATE\n");
823  Emit(os, "#define _CRT_SECURE_NO_DEPRECATE\n");
824  Emit(os, "#endif\n");
825  Emit(os, "\n");
826  Emit(os, "//----------------------------------------------------------------------------\n");
827  Emit(os, "// Forward declare functions that generated code might call...\n");
828  Emit(os, "//\n");
829  Emit(os, "#ifdef _WIN64\n");
830  Emit(os, "extern \"C\" __declspec(dllimport) void* __stdcall CoTaskMemAlloc(unsigned __int64 cb);\n");
831  Emit(os, "#define MUMMY_STRING_ALLOC ::CoTaskMemAlloc\n");
832  Emit(os, "#else\n");
833  Emit(os, "#ifdef _WIN32\n");
834  Emit(os, "extern \"C\" __declspec(dllimport) void* __stdcall CoTaskMemAlloc(unsigned long cb);\n");
835  Emit(os, "#define MUMMY_STRING_ALLOC ::CoTaskMemAlloc\n");
836  Emit(os, "#endif\n");
837  Emit(os, "#endif\n");
838  Emit(os, "\n");
839  Emit(os, "#ifndef MUMMY_STRING_ALLOC\n");
840  Emit(os, "#define MUMMY_STRING_ALLOC malloc\n");
841  Emit(os, "#endif\n");
842  Emit(os, "\n");
843  Emit(os, "//----------------------------------------------------------------------------\n");
844  Emit(os, "// Macro for exporting functions implemented in this file...\n");
845  Emit(os, "//\n");
846  Emit(os, "#ifdef _WIN32\n");
847  Emit(os, "#define MUMMY_DLL_EXPORT __declspec(dllexport)\n");
848  Emit(os, "#else\n");
849  Emit(os, "#define MUMMY_DLL_EXPORT\n");
850  Emit(os, "#endif\n");
851  Emit(os, "\n");
852  Emit(os, "//----------------------------------------------------------------------------\n");
853  Emit(os, "#include \"");
854  Emit(os, header.c_str());
855  Emit(os, "\"\n");
856  Emit(os, "\n");
857 
858 
859  if (IsUtilityClass(c))
860  {
861  // No export layer necessary...
862  }
863  else
864  {
865  // Gather wrapped elements:
866  //
867  gxsys_stl::vector<cable::Method*> wrapped_methods;
868  cable::Method *factoryM = 0;
869  cable::Method *disposalM = 0;
870  cable::Method *registerM = 0;
871  cable::Method *unRegisterM = 0;
872 
873  this->GetCsharpGenerator()->GatherWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM, false);
874 
875  const cable::Constructor* ctor = FindNonAbstractPublicDefaultConstructor(c);
876 
877  bool hasMethodsThatReturnRefs = false;
878  for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin();
879  !hasMethodsThatReturnRefs && mit != wrapped_methods.end(); ++mit)
880  {
881  cable::FunctionType *ft = (*mit)->GetFunctionType();
882  cable::Type *retType = ft->GetReturns();
883  if (cable::Type::ReferenceTypeId == retType->GetTypeId())
884  {
885  hasMethodsThatReturnRefs = true;
886  }
887  }
888 
889  if (hasMethodsThatReturnRefs)
890  {
891  Emit(os, "//----------------------------------------------------------------------------\n");
892  Emit(os, "// Thanks to Brad King for the magic of the ref converter helper class:\n");
893  Emit(os, "template <typename T>\n");
894  Emit(os, "class ref\n");
895  Emit(os, "{\n");
896  Emit(os, "public:\n");
897  EmitIndent(os);
898  Emit(os, "ref() throw(): p_(0) {}\n");
899  EmitIndent(os);
900  Emit(os, "ref<T>& operator=(T& r) throw() { this->p_ = &r; return *this; }\n");
901  EmitIndent(os);
902  Emit(os, "operator T&() throw() { return *this->p_; }\n");
903  Emit(os, "\n");
904  Emit(os, "private:\n");
905  EmitIndent(os);
906  Emit(os, "T* p_;\n");
907  Emit(os, "};\n");
908  }
909 
910 
911  // Emit include statements for any ref counted base classes involved in method return
912  // values. Collect them into a set and then emit the set; has the nice effect of
913  // eliminating duplicates and emitting the include statements in sorted order...
914  //
915  gxsys_stl::set<gxsys_stl::string> includeStatements;
916 
917  gxsys_stl::string registerInclude;
918  if (ctor)
919  {
920  registerInclude = this->GetSettings()->GetRegisterInclude(c);
921  if (!registerInclude.empty())
922  {
923  includeStatements.insert(registerInclude);
924  }
925  }
926 
927  for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin();
928  mit != wrapped_methods.end(); ++mit)
929  {
930  cable::FunctionType *ft = (*mit)->GetFunctionType();
931  cable::Type *retType = ft->GetReturns();
932  if (!HasMapToType(retType) && IsObjectPointer(retType))
933  {
934  const cable::Class* cRetType = cable::ClassType::SafeDownCast(
935  cable::PointerType::SafeDownCast(retType)->GetTarget()
936  )->GetClass();
937  registerInclude = this->GetSettings()->GetRegisterInclude(cRetType);
938  if (!registerInclude.empty())
939  {
940  includeStatements.insert(registerInclude);
941  }
942  }
943  }
944 
945  includeStatements.insert("#include \"MummyRuntime.h\"");
946  includeStatements.insert("#include \"string.h\" // for possible memset use");
947 
948  if (!cws.exceptionInclude.empty())
949  {
950  includeStatements.insert(cws.exceptionInclude);
951  }
952 
953  if (!includeStatements.empty())
954  {
955  Emit(os, "\n");
956  Emit(os, "//----------------------------------------------------------------------------\n");
957 
958  for(gxsys_stl::set<gxsys_stl::string>::iterator sit = includeStatements.begin();
959  sit != includeStatements.end(); ++sit)
960  {
961  Emit(os, sit->c_str());
962  Emit(os, "\n");
963  }
964  }
965 
966 
967  // Special methods first, then iterate the remainder in wrapped_methods:
968  //
969  if (factoryM)
970  {
971  Emit(os, "\n");
972  Emit(os, "\n");
973  Emit(os, "//----------------------------------------------------------------------------\n");
974  EmitClassMethodForExportLayer(os, c, factoryM, factoryM->GetName());
975  }
976 
977  if (disposalM)
978  {
979  Emit(os, "\n");
980  Emit(os, "\n");
981  Emit(os, "//----------------------------------------------------------------------------\n");
982  EmitClassMethodForExportLayer(os, c, disposalM, disposalM->GetName());
983  }
984 
985  if (registerM)
986  {
987  Emit(os, "\n");
988  Emit(os, "\n");
989  Emit(os, "//----------------------------------------------------------------------------\n");
990  EmitClassMethodForExportLayer(os, c, registerM, registerM->GetName());
991  }
992 
993  if (unRegisterM)
994  {
995  Emit(os, "\n");
996  Emit(os, "\n");
997  Emit(os, "//----------------------------------------------------------------------------\n");
998  EmitClassMethodForExportLayer(os, c, unRegisterM, unRegisterM->GetName());
999  }
1000 
1001  // If there's a public default constructor for concrete class 'c', emit "_new"
1002  // and "_delete" export layer functions:
1003  //
1004  if (ctor)
1005  {
1006  Emit(os, "\n");
1007  Emit(os, "\n");
1008  Emit(os, "//----------------------------------------------------------------------------\n");
1009  EmitClassMethodForExportLayer(os, c, ctor, "new");
1010 
1011  Emit(os, "\n");
1012  Emit(os, "\n");
1013  Emit(os, "//----------------------------------------------------------------------------\n");
1014  EmitClassMethodForExportLayer(os, c, ctor, "delete");
1015  }
1016 
1017  for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin();
1018  mit != wrapped_methods.end(); ++mit)
1019  {
1020  Emit(os, "\n");
1021  Emit(os, "\n");
1022  Emit(os, "//----------------------------------------------------------------------------\n");
1023  EmitClassMethodForExportLayer(os, c, *mit, (*mit)->GetName());
1024  }
1025  }
1026 
1027  // If there is extraExportLayerCode, emit it at the bottom of the file.
1028  // If it's there, it's the name of a file that we are to include in
1029  // its entirety...
1030  //
1031  gxsys_stl::string extraCode = this->GetSettings()->GetExtraExportLayerCode(c);
1032  if (extraCode != "")
1033  {
1034  Emit(os, "\n");
1035  Emit(os, "\n");
1036  Emit(os, "//----------------------------------------------------------------------------\n");
1037  Emit(os, "// Begin extraExportLayerCode\n");
1038  Emit(os, "\n");
1039  EmitFile(os, extraCode.c_str());
1040  Emit(os, "\n");
1041  Emit(os, "// End extraExportLayerCode\n");
1042  }
1043 }