mummy
1.0.2
|
00001 //---------------------------------------------------------------------------- 00002 // 00003 // $Id: MummyCsharpExportLayerGenerator.cxx 2 2007-12-17 18:15:56Z david.cole $ 00004 // 00005 // $Author: david.cole $ 00006 // $Date: 2007-12-17 13:15:56 -0500 (Mon, 17 Dec 2007) $ 00007 // $Revision: 2 $ 00008 // 00009 // Copyright (C) 2006-2007 Kitware, Inc. 00010 // 00011 //---------------------------------------------------------------------------- 00012 00013 #include "MummyCsharpExportLayerGenerator.h" 00014 #include "MummyCsharpGenerator.h" 00015 #include "MummyLog.h" 00016 #include "MummySettings.h" 00017 00018 #include "cableClass.h" 00019 #include "cableClassType.h" 00020 #include "cableConstructor.h" 00021 #include "cableFunctionType.h" 00022 #include "cableMethod.h" 00023 #include "cablePointerType.h" 00024 #include "cableReferenceType.h" 00025 #include "cxxCvQualifiedType.h" 00026 #include "cxxFunctionType.h" 00027 #include "cxxPointerType.h" 00028 #include "cxxType.h" 00029 00030 #include "gxsys/stl/set" 00031 #include "gxsys/SystemTools.hxx" 00032 00033 00034 //---------------------------------------------------------------------------- 00035 MummyCsharpExportLayerGenerator::MummyCsharpExportLayerGenerator() 00036 { 00037 this->CsharpGenerator = 0; 00038 } 00039 00040 00041 //---------------------------------------------------------------------------- 00042 MummyCsharpExportLayerGenerator::~MummyCsharpExportLayerGenerator() 00043 { 00044 } 00045 00046 00047 //---------------------------------------------------------------------------- 00048 bool MummyCsharpExportLayerGenerator::GenerateWrappers() 00049 { 00050 this->EmitClassForExportLayer(*GetStream(), GetTargetClass()); 00051 return false; 00052 } 00053 00054 00055 //---------------------------------------------------------------------------- 00056 MummyCsharpGenerator* MummyCsharpExportLayerGenerator::GetCsharpGenerator() 00057 { 00058 return this->CsharpGenerator; 00059 } 00060 00061 00062 //---------------------------------------------------------------------------- 00063 void MummyCsharpExportLayerGenerator::SetCsharpGenerator(MummyCsharpGenerator* generator) 00064 { 00065 this->CsharpGenerator = generator; 00066 } 00067 00068 00069 //---------------------------------------------------------------------------- 00070 //bool MummyCsharpExportLayerGenerator::FundamentalTypeIsWrappable(const cable::Type* t) 00071 //{ 00072 // return this->GetCsharpGenerator()->FundamentalTypeIsWrappable(t); 00073 //} 00074 00075 00076 //---------------------------------------------------------------------------- 00077 //bool MummyCsharpExportLayerGenerator::TypeIsWrappable(const cable::Type* t) 00078 //{ 00079 // return this->GetCsharpGenerator()->TypeIsWrappable(t); 00080 //} 00081 00082 00083 //---------------------------------------------------------------------------- 00084 //bool MummyCsharpExportLayerGenerator::FunctionTypeIsWrappable(const cable::FunctionType* ft) 00085 //{ 00086 // return this->GetCsharpGenerator()->FunctionTypeIsWrappable(ft); 00087 //} 00088 00089 00090 //---------------------------------------------------------------------------- 00091 //bool MummyCsharpExportLayerGenerator::MethodIsWrappable(const cable::Method* m, const cable::Context::Access& access) 00092 //{ 00093 // return this->GetCsharpGenerator()->MethodIsWrappable(m, access); 00094 //} 00095 00096 00097 //---------------------------------------------------------------------------- 00098 //bool MummyCsharpExportLayerGenerator::ClassIsWrappable(const cable::Class* c) 00099 //{ 00100 // return this->GetCsharpGenerator()->ClassIsWrappable(c); 00101 //} 00102 00103 00104 //---------------------------------------------------------------------------- 00105 const char *MummyCsharpExportLayerGenerator::GetArgName(cable::FunctionType *ftype, unsigned int i) 00106 { 00107 return this->GetCsharpGenerator()->GetArgName(ftype, i); 00108 } 00109 00110 00111 //---------------------------------------------------------------------------- 00112 gxsys_stl::string MummyCsharpExportLayerGenerator::GetExportLayerFunctionName(const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname) 00113 { 00114 return this->GetCsharpGenerator()->GetExportLayerFunctionName(c, m, mname); 00115 } 00116 00117 00118 //---------------------------------------------------------------------------- 00119 gxsys_stl::string GetExportLayerActualType(cable::Type *t, bool stripConst) 00120 { 00121 gxsys_stl::string s(t->GetCxxType().GetName()); 00122 00123 if (stripConst) 00124 { 00125 s = t->GetCxxType().GetType()->GenerateName("", false, false); 00126 } 00127 00128 return s; 00129 } 00130 00131 00132 //---------------------------------------------------------------------------- 00133 gxsys_stl::string GetExportLayerMappedType(cable::Type *t, bool stripConst) 00134 { 00135 gxsys_stl::string s; 00136 00137 if (HasMapToType(t)) 00138 { 00139 // 't' should be either a class or a reference to a class... 00140 // 00141 cable::Class* c = 0; 00142 00143 if (cable::Type::ClassTypeId == t->GetTypeId()) 00144 { 00145 c = cable::ClassType::SafeDownCast(t)->GetClass(); 00146 } 00147 else if (cable::Type::ReferenceTypeId == t->GetTypeId()) 00148 { 00149 c = cable::ClassType::SafeDownCast( 00150 cable::ReferenceType::SafeDownCast(t)->GetTarget())->GetClass(); 00151 } 00152 00153 if (c) 00154 { 00155 s = ExtractMapToType(c); 00156 } 00157 00158 // Abstract "string" type translates to "const char*" in the export layer: 00159 // 00160 if (s == "string") 00161 { 00162 if (stripConst) 00163 { 00164 s = "char*"; 00165 } 00166 else 00167 { 00168 s = "const char*"; 00169 } 00170 } 00171 else 00172 { 00173 s = "ERROR_unknown_mapped_to_type_or_null_class_type_in_the_export_layer"; 00174 LogError(me_InternalError, << s.c_str()); 00175 } 00176 } 00177 else 00178 { 00179 s = GetExportLayerActualType(t, stripConst); 00180 } 00181 00182 return s; 00183 } 00184 00185 00186 //---------------------------------------------------------------------------- 00187 gxsys_stl::string MummyCsharpExportLayerGenerator::GetArgTypeAndNameString(cable::Type *argType, const char *name, bool stripConst) 00188 { 00189 gxsys_stl::string s; 00190 00191 if ((argType->GetTypeId() == cable::Type::PointerTypeId) && 00192 (cable::PointerType::SafeDownCast(argType)->GetTarget()->GetTypeId() == cable::Type::FunctionTypeId) 00193 ) 00194 { 00195 if (EquivalentTypedefNameExists(this->GetTargetClass(), cable::FunctionType::SafeDownCast(cable::PointerType::SafeDownCast(argType)->GetTarget()), s)) 00196 { 00197 s = gxsys_stl::string(GetFullyQualifiedNameForCPlusPlus(this->GetTargetClass())) + "::" + s; 00198 } 00199 else 00200 { 00201 s = "ERROR - cannot generate argTypeAndName string for function pointer - add a typedef for the function pointer..."; 00202 LogError(me_InternalError, << s.c_str()); 00203 } 00204 } 00205 else 00206 { 00207 s = GetExportLayerMappedType(argType, stripConst); 00208 } 00209 00210 if (name) 00211 { 00212 s += " "; 00213 s += name; 00214 } 00215 00216 return s; 00217 } 00218 00219 00220 //---------------------------------------------------------------------------- 00221 void MummyCsharpExportLayerGenerator::EmitClassMethodDeclarationForExportLayer(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, bool emitExceptionParams) 00222 { 00223 gxsys_stl::string cname(GetFullyQualifiedNameForCPlusPlus(c)); 00224 gxsys_stl::string s; 00225 cable::FunctionType *ft = m->GetFunctionType(); 00226 unsigned int cArgs = ft->GetNumberOfArguments(); 00227 unsigned int cArgsEmitted = 0; 00228 unsigned int i = 0; 00229 cable::Type *retType = ft->GetReturns(); 00230 cable::Type *argType = 0; 00231 cable::Class* cByRefClass = 0; 00232 00233 // Extern "C": 00234 Emit(os, "extern \"C\" "); 00235 00236 // Export declspec: 00237 Emit(os, "MUMMY_DLL_EXPORT\n"); 00238 00239 // Special case "new" and "delete" -- the rest are strictly according to the 00240 // method definition as given by 'm'... 00241 // 00242 if (mname == "new") 00243 { 00244 // Return type: 00245 Emit(os, cname.c_str()); 00246 Emit(os, "* "); 00247 00248 // Exported function name: 00249 Emit(os, GetExportLayerFunctionName(c, m, mname).c_str()); 00250 00251 Emit(os, "(unsigned int* mteStatus, unsigned int* mteIndex, unsigned int* rawRefCount"); 00252 cArgsEmitted += 3; 00253 00254 if (emitExceptionParams) 00255 { 00256 Emit(os, ", unsigned int* mteExceptionIndex, void** clonedException"); 00257 cArgsEmitted += 2; 00258 } 00259 00260 Emit(os, ")\n"); 00261 } 00262 else if (mname == "delete") 00263 { 00264 // Return type: 00265 Emit(os, "void"); 00266 Emit(os, " "); 00267 00268 // Exported function name: 00269 Emit(os, GetExportLayerFunctionName(c, m, mname).c_str()); 00270 00271 Emit(os, "("); 00272 Emit(os, cname.c_str()); 00273 Emit(os, "* pThis"); 00274 cArgsEmitted += 1; 00275 00276 if (emitExceptionParams) 00277 { 00278 Emit(os, ", unsigned int* mteExceptionIndex, void** clonedException"); 00279 cArgsEmitted += 2; 00280 } 00281 00282 Emit(os, ")\n"); 00283 } 00284 else 00285 { 00286 // Return type: 00287 Emit(os, GetArgTypeAndNameString(retType, 0, false).c_str()); 00288 Emit(os, " "); 00289 00290 // Exported function name: 00291 Emit(os, GetExportLayerFunctionName(c, m, mname).c_str()); 00292 00293 // Open args: 00294 Emit(os, "("); 00295 00296 // The "this" arg: 00297 if (!m->GetStatic()) 00298 { 00299 Emit(os, cname.c_str()); 00300 Emit(os, "* pThis"); 00301 cArgsEmitted += 1; 00302 00303 if (cArgs!=0) 00304 { 00305 Emit(os, ", "); 00306 } 00307 } 00308 00309 // The real args: 00310 for (i= 0; i<cArgs; ++i) 00311 { 00312 argType = ft->GetArgument(i); 00313 00314 // Utility classes get marshalled as copies across the boundary from C# 00315 // even if in C++ they are & (byref) arguments... So they need to be 00316 // declared as just plain old stack-based by value arguments here. 00317 // 00318 cByRefClass = 0; 00319 00320 if (cable::Type::ReferenceTypeId == argType->GetTypeId()) 00321 { 00322 cable::ClassType* classType = cable::ClassType::SafeDownCast( 00323 cable::ReferenceType::SafeDownCast(argType)->GetTarget()); 00324 if (classType) 00325 { 00326 cByRefClass = classType->GetClass(); 00327 } 00328 } 00329 00330 if (cByRefClass && IsUtilityClass(cByRefClass)) 00331 { 00332 Emit(os, GetFullyQualifiedNameForCPlusPlus(cByRefClass).c_str()); 00333 Emit(os, " "); 00334 Emit(os, GetArgName(ft, i)); 00335 } 00336 else 00337 { 00338 Emit(os, GetArgTypeAndNameString(argType, GetArgName(ft, i), false).c_str()); 00339 } 00340 00341 cArgsEmitted += 1; 00342 00343 if (i<cArgs-1) 00344 { 00345 Emit(os, ", "); 00346 } 00347 } 00348 00349 // Add "generated args" to method signatures that return object pointers: 00350 // 00351 if (!HasMapToType(retType) && IsObjectPointer(retType)) 00352 { 00353 if (cArgsEmitted) 00354 { 00355 Emit(os, ", "); 00356 } 00357 00358 Emit(os, "unsigned int* mteStatus, unsigned int* mteIndex, unsigned int* rawRefCount"); 00359 cArgsEmitted += 3; 00360 } 00361 00362 if (emitExceptionParams) 00363 { 00364 if (cArgsEmitted) 00365 { 00366 Emit(os, ", "); 00367 } 00368 00369 Emit(os, "unsigned int* mteExceptionIndex, void** clonedException"); 00370 cArgsEmitted += 2; 00371 } 00372 00373 // Close args: 00374 Emit(os, ")\n"); 00375 } 00376 } 00377 00378 00379 //---------------------------------------------------------------------------- 00380 void MummyCsharpExportLayerGenerator::EmitSpecialHandlingForObjectPointerReturns(gxsys_ios::ostream &os, const gxsys_stl::string& cname, const cable::Method *, const gxsys_stl::string&, const unsigned int indent) 00381 { 00382 ClassWrappingSettings cws; 00383 if (!this->GetSettings()->FindClassWrappingSettings(cname.c_str(), &cws)) 00384 { 00385 LogError(me_NoClassWrappingSettings, 00386 << "error: no ClassWrappingSettings for class " << cname.c_str()); 00387 } 00388 00389 EmitIndent(os, indent); 00390 Emit(os, "if (0 != rv)\n"); 00391 EmitIndent(os, indent+1); 00392 Emit(os, "{\n"); 00393 00394 gxsys_stl::string registerMethod = cws.registerMethod; 00395 gxsys_stl::string registerBaseClass = cws.registerBaseClass; 00396 gxsys_stl::string getRefCountMethod = cws.getRefCountMethod; 00397 gxsys_stl::string getMummyTypeEntryMethod = cws.getMummyTypeEntryMethod; 00398 gxsys_stl::string setMummyTypeEntryMethod = cws.setMummyTypeEntryMethod; 00399 00400 if (!registerMethod.empty()) 00401 { 00402 EmitIndent(os, indent+1); 00403 Emit(os, registerBaseClass.c_str()); 00404 Emit(os, "* ro = ("); 00405 Emit(os, registerBaseClass.c_str()); 00406 Emit(os, "*) (void*) rv;\n"); 00407 } 00408 00409 00410 if (!registerMethod.empty() && !getMummyTypeEntryMethod.empty()) 00411 { 00412 // If object supports MummyTypeEntry caching: 00413 // 00414 EmitIndent(os, indent+1); 00415 Emit(os, "Kitware::mummy::TypeEntry* entry = ro->"); 00416 Emit(os, getMummyTypeEntryMethod.c_str()); 00417 Emit(os, "();\n"); 00418 EmitIndent(os, indent+1); 00419 Emit(os, "if (!entry)\n"); 00420 EmitIndent(os, indent+2); 00421 Emit(os, "{\n"); 00422 EmitIndent(os, indent+2); 00423 Emit(os, "entry = Kitware::mummy::Runtime::GetTypeEntry((void*) rv, typeid(*ro).name());\n"); 00424 EmitIndent(os, indent+2); 00425 Emit(os, "ro->"); 00426 Emit(os, setMummyTypeEntryMethod.c_str()); 00427 Emit(os, "(entry);\n"); 00428 EmitIndent(os, indent+2); 00429 Emit(os, "*mteStatus = 1;\n"); 00430 EmitIndent(os, indent+2); 00431 Emit(os, "}\n"); 00432 EmitIndent(os, indent+1); 00433 Emit(os, "else\n"); 00434 EmitIndent(os, indent+2); 00435 Emit(os, "{\n"); 00436 EmitIndent(os, indent+2); 00437 Emit(os, "*mteStatus = 2;\n"); 00438 EmitIndent(os, indent+2); 00439 Emit(os, "}\n"); 00440 } 00441 else 00442 { 00443 // ...otherwise always call Runtime::GetTypeEntry: 00444 // 00445 EmitIndent(os, indent+1); 00446 Emit(os, "Kitware::mummy::TypeEntry* entry = Kitware::mummy::Runtime::GetTypeEntry(\n"); 00447 00448 EmitIndent(os, indent+2); 00449 Emit(os, "(void*) rv, typeid(*"); 00450 if (!registerMethod.empty()) 00451 { 00452 // Prefer "ro" (if we have it) to "rv" simply because 00453 // typeid(*obj).name() is really really stupid. 00454 // 00455 Emit(os, "ro"); 00456 } 00457 else 00458 { 00459 Emit(os, "rv"); 00460 } 00461 Emit(os, ").name());\n"); 00462 00463 EmitIndent(os, indent+1); 00464 Emit(os, "*mteStatus = 0;\n"); 00465 } 00466 00467 // So here we always have an entry: 00468 // 00469 EmitIndent(os, indent+1); 00470 Emit(os, "*mteIndex = entry->GetIndex();\n"); 00471 00472 if (!registerMethod.empty() && !getRefCountMethod.empty()) 00473 { 00474 EmitIndent(os, indent+1); 00475 Emit(os, "*rawRefCount = (unsigned int) ro->"); 00476 Emit(os, getRefCountMethod.c_str()); 00477 Emit(os, ";\n"); 00478 } 00479 else 00480 { 00481 EmitIndent(os, indent+1); 00482 Emit(os, "*rawRefCount = (unsigned int) -86;\n"); 00483 } 00484 00485 EmitIndent(os, indent+1); 00486 Emit(os, "}\n"); 00487 } 00488 00489 00490 //---------------------------------------------------------------------------- 00491 void MummyCsharpExportLayerGenerator::EmitClassMethodForExportLayer(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname) 00492 { 00493 gxsys_stl::string cname(GetFullyQualifiedNameForCPlusPlus(c)); 00494 cable::FunctionType *ft = m->GetFunctionType(); 00495 unsigned int cArgs = ft->GetNumberOfArguments(); 00496 unsigned int i = 0; 00497 unsigned int indent = 1; 00498 cable::Type *retType = ft->GetReturns(); 00499 cable::PointerType::Pointer fakeRetType; 00500 bool voidReturn = false; 00501 bool mappedReturnType = false; 00502 bool emitExceptionBlock = false; 00503 gxsys_stl::string rvTypeStr; 00504 bool needsInit = false; 00505 gxsys_stl::string initExpression; 00506 00507 ClassWrappingSettings cws; 00508 if (!this->GetSettings()->FindClassWrappingSettings(GetFullyQualifiedNameForCPlusPlus(c).c_str(), &cws)) 00509 { 00510 LogError(me_NoClassWrappingSettings, 00511 << "error: no ClassWrappingSettings for class " << GetFullyQualifiedNameForCPlusPlus(c).c_str()); 00512 } 00513 00514 emitExceptionBlock = !cws.exceptionBaseClass.empty(); 00515 00516 // If mname is "new" fake retType: 00517 // 00518 if (mname == "new") 00519 { 00520 fakeRetType = cable::PointerType::New(); 00521 fakeRetType->SetTarget(c->GetClassType()); 00522 fakeRetType->CreateCxxType(this->GetSourceRepresentation()->GetTypeSystem()); 00523 retType = fakeRetType; 00524 } 00525 00526 // Is there a return value? Do we need to map/transform it to a different type? 00527 // 00528 if (IsVoid(retType)) 00529 { 00530 voidReturn = true; 00531 } 00532 else if (HasMapToType(retType)) 00533 { 00534 mappedReturnType = true; 00535 } 00536 00537 // Declaration: 00538 EmitClassMethodDeclarationForExportLayer(os, c, m, mname, emitExceptionBlock); 00539 00540 // Open body: 00541 Emit(os, "{\n"); 00542 00543 // Declare return value "rv": 00544 if (!voidReturn) 00545 { 00546 if (cable::Type::ReferenceTypeId == retType->GetTypeId()) 00547 { 00548 rvTypeStr = gxsys_stl::string("ref<") + GetArgTypeAndNameString( 00549 cable::ReferenceType::SafeDownCast(retType)->GetTarget(), 0, false) + ">"; 00550 needsInit = false; 00551 } 00552 else if (mappedReturnType) 00553 { 00554 rvTypeStr = GetArgTypeAndNameString(retType, 0, true); 00555 needsInit = true; 00556 00557 initExpression = "cast"; 00558 // david.cole::fix -- this works for the only mapped type we currently 00559 // support ("string" / "const char*") -- it needs to be generalized 00560 // to generate correct code if we ever introduce more mapped types... 00561 } 00562 else 00563 { 00564 rvTypeStr = GetArgTypeAndNameString(retType, 0, true); 00565 needsInit = true; 00566 00567 initExpression = GetCPlusPlusZeroInitializerExpression(retType); 00568 } 00569 00570 EmitIndent(os); 00571 Emit(os, rvTypeStr.c_str()); 00572 Emit(os, " rv"); 00573 00574 if (needsInit) 00575 { 00576 if (initExpression == "memset") 00577 { 00578 Emit(os, ";\n"); 00579 EmitIndent(os); 00580 Emit(os, "memset(&rv, 0, sizeof(rv))"); 00581 } 00582 else if (initExpression == "cast") 00583 { 00584 Emit(os, " = ("); 00585 Emit(os, rvTypeStr.c_str()); 00586 Emit(os, ") 0"); 00587 } 00588 else 00589 { 00590 Emit(os, " = "); 00591 Emit(os, initExpression.c_str()); 00592 } 00593 } 00594 00595 Emit(os, ";"); 00596 Emit(os, "\n"); 00597 Emit(os, "\n"); 00598 } 00599 00600 // Open exception try block: 00601 if (emitExceptionBlock) 00602 { 00603 EmitIndent(os); 00604 Emit(os, "try\n"); 00605 EmitIndent(os); 00606 Emit(os, "{\n"); 00607 00608 indent++; 00609 } 00610 00611 // Delegate the call to the real underlying object: 00612 EmitIndent(os, indent); 00613 00614 if (!voidReturn) 00615 { 00616 if (mappedReturnType) 00617 { 00618 Emit(os, GetExportLayerActualType(retType, true).c_str()); 00619 Emit(os, " rvmi = "); 00620 } 00621 else 00622 { 00623 Emit(os, "rv = "); 00624 } 00625 } 00626 00627 // Special case "new" and "delete" -- the rest are strictly according to the 00628 // method definition as given by 'm'... 00629 // 00630 if (mname == "new") 00631 { 00632 Emit(os, "new "); 00633 Emit(os, cname.c_str()); 00634 Emit(os, ";"); 00635 Emit(os, "\n"); 00636 } 00637 else if (mname == "delete") 00638 { 00639 Emit(os, "delete pThis;"); 00640 Emit(os, "\n"); 00641 } 00642 else 00643 { 00644 if (!m->GetStatic()) 00645 { 00646 Emit(os, "pThis->"); 00647 } 00648 else 00649 { 00650 Emit(os, cname.c_str()); 00651 Emit(os, "::"); 00652 } 00653 00654 Emit(os, mname.c_str()); 00655 Emit(os, "("); 00656 for (i= 0; i<cArgs; ++i) 00657 { 00658 Emit(os, GetArgName(ft, i)); 00659 00660 if (i<cArgs-1) 00661 { 00662 Emit(os, ", "); 00663 } 00664 } 00665 Emit(os, ");"); 00666 Emit(os, "\n"); 00667 } 00668 00669 00670 // Map return type from "rvmi" to "rv": 00671 // 00672 if (mappedReturnType) 00673 { 00674 gxsys_stl::string map_to_type = GetMapToType(retType); 00675 gxsys_stl::string mapping_method = GetStringMethod(retType); 00676 00677 Emit(os, "\n"); 00678 00679 EmitIndent(os, indent); 00680 Emit(os, GetExportLayerMappedType(retType, false).c_str()); 00681 Emit(os, " rvm = rvmi."); 00682 Emit(os, mapping_method.c_str()); 00683 Emit(os, "();\n"); 00684 00685 if (map_to_type == "string") 00686 { 00687 EmitIndent(os, indent); 00688 Emit(os, "size_t n = 0;\n"); 00689 Emit(os, "\n"); 00690 EmitIndent(os, indent); 00691 Emit(os, "if (rvm)\n"); 00692 EmitIndent(os, indent+1); 00693 Emit(os, "{\n"); 00694 EmitIndent(os, indent+1); 00695 Emit(os, "n = strlen(rvm);\n"); 00696 EmitIndent(os, indent+1); 00697 Emit(os, "}\n"); 00698 Emit(os, "\n"); 00699 EmitIndent(os, indent); 00700 Emit(os, "rv = (char*) MUMMY_STRING_ALLOC(n+1);\n"); 00701 EmitIndent(os, indent); 00702 Emit(os, "if (rv)\n"); 00703 EmitIndent(os, indent+1); 00704 Emit(os, "{\n"); 00705 EmitIndent(os, indent+1); 00706 Emit(os, "strncpy(rv, rvm, n);\n"); 00707 EmitIndent(os, indent+1); 00708 Emit(os, "rv[n] = 0;\n"); 00709 EmitIndent(os, indent+1); 00710 Emit(os, "}\n"); 00711 Emit(os, "\n"); 00712 } 00713 else 00714 { 00715 LogFileLineErrorMsg(m->GetFile(), m->GetLine(), me_UnknownMapToType, 00716 << "Unknown iwhMapToType for return type of method '" << m->GetName() << "'"); 00717 } 00718 } 00719 else if (IsObjectPointer(retType)) 00720 { 00721 const cable::Class* cRetType = cable::ClassType::SafeDownCast( 00722 cable::PointerType::SafeDownCast(retType)->GetTarget() 00723 )->GetClass(); 00724 00725 this->EmitSpecialHandlingForObjectPointerReturns(os, GetFullyQualifiedNameForCPlusPlus(cRetType), m, mname, indent); 00726 } 00727 00728 // Close exception try block: 00729 if (emitExceptionBlock) 00730 { 00731 EmitIndent(os); 00732 Emit(os, "}\n"); 00733 EmitIndent(os); 00734 Emit(os, "catch("); 00735 Emit(os, cws.exceptionBaseClass.c_str()); 00736 Emit(os, "& mel_exc)\n"); 00737 EmitIndent(os); 00738 Emit(os, "{\n"); 00739 00740 EmitIndent(os, 2); 00741 Emit(os, cws.exceptionBaseClass.c_str()); 00742 Emit(os, "* mel_exc_clone = mel_exc."); 00743 Emit(os, cws.exceptionCloneMethod.c_str()); 00744 Emit(os, "();\n"); 00745 00746 EmitIndent(os, 2); 00747 Emit(os, "Kitware::mummy::TypeEntry* entry = Kitware::mummy::Runtime::GetTypeEntry(\n"); 00748 00749 EmitIndent(os, 3); 00750 Emit(os, "(void*) mel_exc_clone, typeid(*mel_exc_clone).name());\n"); 00751 00752 EmitIndent(os, 2); 00753 Emit(os, "*clonedException = mel_exc_clone;\n"); 00754 00755 EmitIndent(os, 2); 00756 Emit(os, "*mteExceptionIndex = entry->GetIndex();\n"); 00757 00758 EmitIndent(os); 00759 Emit(os, "}\n"); 00760 } 00761 00762 // Return statement: 00763 if (!voidReturn) 00764 { 00765 Emit(os, "\n"); 00766 EmitIndent(os); 00767 Emit(os, "return rv;\n"); 00768 } 00769 00770 // Close body: 00771 Emit(os, "}\n"); 00772 } 00773 00774 00775 //---------------------------------------------------------------------------- 00776 void MummyCsharpExportLayerGenerator::EmitClassForExportLayer(gxsys_ios::ostream &os, const cable::Class *c) 00777 { 00778 gxsys_stl::string header(c->GetFile()); 00779 00780 ClassWrappingSettings cws; 00781 if (!this->GetSettings()->FindClassWrappingSettings(GetFullyQualifiedNameForCPlusPlus(c).c_str(), &cws)) 00782 { 00783 LogError(me_NoClassWrappingSettings, 00784 << "error: no ClassWrappingSettings for class " << GetFullyQualifiedNameForCPlusPlus(c).c_str()); 00785 } 00786 00787 // Emit code: 00788 // 00789 EmitMummyVersionComments(os, "//"); 00790 00791 // If the class maps directly to a builtin type, then DO NOT emit any code. 00792 // 00793 gxsys_stl::string mapToType = ExtractMapToType(c); 00794 if (mapToType != "") 00795 { 00796 Emit(os, "\n"); 00797 Emit(os, "//----------------------------------------------------------------------------\n"); 00798 Emit(os, "// Unmanaged class '"); 00799 Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str()); 00800 Emit(os, "' maps directly to type '"); 00801 Emit(os, mapToType.c_str()); 00802 Emit(os, "'.\n"); 00803 Emit(os, "// No code generated for '"); 00804 Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str()); 00805 Emit(os, "'...\n"); 00806 00807 LogVerboseInfo(<< "Skipping code generation because class maps directly to native type."); 00808 00809 return; 00810 } 00811 00812 Emit(os, "\n"); 00813 Emit(os, "//----------------------------------------------------------------------------\n"); 00814 Emit(os, "// You can use this symbol in your header files if there are bits of your\n"); 00815 Emit(os, "// code that should be conditionally compiled in this export layer.\n"); 00816 Emit(os, "//\n"); 00817 Emit(os, "#define MUMMY_EXPORT_LAYER_CXX\n"); 00818 Emit(os, "\n"); 00819 Emit(os, "//----------------------------------------------------------------------------\n"); 00820 Emit(os, "// Do not emit the silly C4996 warning for strncpy use:\n"); 00821 Emit(os, "//\n"); 00822 Emit(os, "#ifndef _CRT_SECURE_NO_DEPRECATE\n"); 00823 Emit(os, "#define _CRT_SECURE_NO_DEPRECATE\n"); 00824 Emit(os, "#endif\n"); 00825 Emit(os, "\n"); 00826 Emit(os, "//----------------------------------------------------------------------------\n"); 00827 Emit(os, "// Forward declare functions that generated code might call...\n"); 00828 Emit(os, "//\n"); 00829 Emit(os, "#ifdef _WIN64\n"); 00830 Emit(os, "extern \"C\" __declspec(dllimport) void* __stdcall CoTaskMemAlloc(unsigned __int64 cb);\n"); 00831 Emit(os, "#define MUMMY_STRING_ALLOC ::CoTaskMemAlloc\n"); 00832 Emit(os, "#else\n"); 00833 Emit(os, "#ifdef _WIN32\n"); 00834 Emit(os, "extern \"C\" __declspec(dllimport) void* __stdcall CoTaskMemAlloc(unsigned long cb);\n"); 00835 Emit(os, "#define MUMMY_STRING_ALLOC ::CoTaskMemAlloc\n"); 00836 Emit(os, "#endif\n"); 00837 Emit(os, "#endif\n"); 00838 Emit(os, "\n"); 00839 Emit(os, "#ifndef MUMMY_STRING_ALLOC\n"); 00840 Emit(os, "#define MUMMY_STRING_ALLOC malloc\n"); 00841 Emit(os, "#endif\n"); 00842 Emit(os, "\n"); 00843 Emit(os, "//----------------------------------------------------------------------------\n"); 00844 Emit(os, "// Macro for exporting functions implemented in this file...\n"); 00845 Emit(os, "//\n"); 00846 Emit(os, "#ifdef _WIN32\n"); 00847 Emit(os, "#define MUMMY_DLL_EXPORT __declspec(dllexport)\n"); 00848 Emit(os, "#else\n"); 00849 Emit(os, "#define MUMMY_DLL_EXPORT\n"); 00850 Emit(os, "#endif\n"); 00851 Emit(os, "\n"); 00852 Emit(os, "//----------------------------------------------------------------------------\n"); 00853 Emit(os, "#include \""); 00854 Emit(os, header.c_str()); 00855 Emit(os, "\"\n"); 00856 Emit(os, "\n"); 00857 00858 00859 if (IsUtilityClass(c)) 00860 { 00861 // No export layer necessary... 00862 } 00863 else 00864 { 00865 // Gather wrapped elements: 00866 // 00867 gxsys_stl::vector<cable::Method*> wrapped_methods; 00868 cable::Method *factoryM = 0; 00869 cable::Method *disposalM = 0; 00870 cable::Method *registerM = 0; 00871 cable::Method *unRegisterM = 0; 00872 00873 this->GetCsharpGenerator()->GatherWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM, false); 00874 00875 const cable::Constructor* ctor = FindNonAbstractPublicDefaultConstructor(c); 00876 00877 bool hasMethodsThatReturnRefs = false; 00878 for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin(); 00879 !hasMethodsThatReturnRefs && mit != wrapped_methods.end(); ++mit) 00880 { 00881 cable::FunctionType *ft = (*mit)->GetFunctionType(); 00882 cable::Type *retType = ft->GetReturns(); 00883 if (cable::Type::ReferenceTypeId == retType->GetTypeId()) 00884 { 00885 hasMethodsThatReturnRefs = true; 00886 } 00887 } 00888 00889 if (hasMethodsThatReturnRefs) 00890 { 00891 Emit(os, "//----------------------------------------------------------------------------\n"); 00892 Emit(os, "// Thanks to Brad King for the magic of the ref converter helper class:\n"); 00893 Emit(os, "template <typename T>\n"); 00894 Emit(os, "class ref\n"); 00895 Emit(os, "{\n"); 00896 Emit(os, "public:\n"); 00897 EmitIndent(os); 00898 Emit(os, "ref() throw(): p_(0) {}\n"); 00899 EmitIndent(os); 00900 Emit(os, "ref<T>& operator=(T& r) throw() { this->p_ = &r; return *this; }\n"); 00901 EmitIndent(os); 00902 Emit(os, "operator T&() throw() { return *this->p_; }\n"); 00903 Emit(os, "\n"); 00904 Emit(os, "private:\n"); 00905 EmitIndent(os); 00906 Emit(os, "T* p_;\n"); 00907 Emit(os, "};\n"); 00908 } 00909 00910 00911 // Emit include statements for any ref counted base classes involved in method return 00912 // values. Collect them into a set and then emit the set; has the nice effect of 00913 // eliminating duplicates and emitting the include statements in sorted order... 00914 // 00915 gxsys_stl::set<gxsys_stl::string> includeStatements; 00916 00917 gxsys_stl::string registerInclude; 00918 if (ctor) 00919 { 00920 registerInclude = this->GetSettings()->GetRegisterInclude(c); 00921 if (!registerInclude.empty()) 00922 { 00923 includeStatements.insert(registerInclude); 00924 } 00925 } 00926 00927 for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin(); 00928 mit != wrapped_methods.end(); ++mit) 00929 { 00930 cable::FunctionType *ft = (*mit)->GetFunctionType(); 00931 cable::Type *retType = ft->GetReturns(); 00932 if (!HasMapToType(retType) && IsObjectPointer(retType)) 00933 { 00934 const cable::Class* cRetType = cable::ClassType::SafeDownCast( 00935 cable::PointerType::SafeDownCast(retType)->GetTarget() 00936 )->GetClass(); 00937 registerInclude = this->GetSettings()->GetRegisterInclude(cRetType); 00938 if (!registerInclude.empty()) 00939 { 00940 includeStatements.insert(registerInclude); 00941 } 00942 } 00943 } 00944 00945 includeStatements.insert("#include \"MummyRuntime.h\""); 00946 includeStatements.insert("#include \"string.h\" // for possible memset use"); 00947 00948 if (!cws.exceptionInclude.empty()) 00949 { 00950 includeStatements.insert(cws.exceptionInclude); 00951 } 00952 00953 if (!includeStatements.empty()) 00954 { 00955 Emit(os, "\n"); 00956 Emit(os, "//----------------------------------------------------------------------------\n"); 00957 00958 for(gxsys_stl::set<gxsys_stl::string>::iterator sit = includeStatements.begin(); 00959 sit != includeStatements.end(); ++sit) 00960 { 00961 Emit(os, sit->c_str()); 00962 Emit(os, "\n"); 00963 } 00964 } 00965 00966 00967 // Special methods first, then iterate the remainder in wrapped_methods: 00968 // 00969 if (factoryM) 00970 { 00971 Emit(os, "\n"); 00972 Emit(os, "\n"); 00973 Emit(os, "//----------------------------------------------------------------------------\n"); 00974 EmitClassMethodForExportLayer(os, c, factoryM, factoryM->GetName()); 00975 } 00976 00977 if (disposalM) 00978 { 00979 Emit(os, "\n"); 00980 Emit(os, "\n"); 00981 Emit(os, "//----------------------------------------------------------------------------\n"); 00982 EmitClassMethodForExportLayer(os, c, disposalM, disposalM->GetName()); 00983 } 00984 00985 if (registerM) 00986 { 00987 Emit(os, "\n"); 00988 Emit(os, "\n"); 00989 Emit(os, "//----------------------------------------------------------------------------\n"); 00990 EmitClassMethodForExportLayer(os, c, registerM, registerM->GetName()); 00991 } 00992 00993 if (unRegisterM) 00994 { 00995 Emit(os, "\n"); 00996 Emit(os, "\n"); 00997 Emit(os, "//----------------------------------------------------------------------------\n"); 00998 EmitClassMethodForExportLayer(os, c, unRegisterM, unRegisterM->GetName()); 00999 } 01000 01001 // If there's a public default constructor for concrete class 'c', emit "_new" 01002 // and "_delete" export layer functions: 01003 // 01004 if (ctor) 01005 { 01006 Emit(os, "\n"); 01007 Emit(os, "\n"); 01008 Emit(os, "//----------------------------------------------------------------------------\n"); 01009 EmitClassMethodForExportLayer(os, c, ctor, "new"); 01010 01011 Emit(os, "\n"); 01012 Emit(os, "\n"); 01013 Emit(os, "//----------------------------------------------------------------------------\n"); 01014 EmitClassMethodForExportLayer(os, c, ctor, "delete"); 01015 } 01016 01017 for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin(); 01018 mit != wrapped_methods.end(); ++mit) 01019 { 01020 Emit(os, "\n"); 01021 Emit(os, "\n"); 01022 Emit(os, "//----------------------------------------------------------------------------\n"); 01023 EmitClassMethodForExportLayer(os, c, *mit, (*mit)->GetName()); 01024 } 01025 } 01026 01027 // If there is extraExportLayerCode, emit it at the bottom of the file. 01028 // If it's there, it's the name of a file that we are to include in 01029 // its entirety... 01030 // 01031 gxsys_stl::string extraCode = this->GetSettings()->GetExtraExportLayerCode(c); 01032 if (extraCode != "") 01033 { 01034 Emit(os, "\n"); 01035 Emit(os, "\n"); 01036 Emit(os, "//----------------------------------------------------------------------------\n"); 01037 Emit(os, "// Begin extraExportLayerCode\n"); 01038 Emit(os, "\n"); 01039 EmitFile(os, extraCode.c_str()); 01040 Emit(os, "\n"); 01041 Emit(os, "// End extraExportLayerCode\n"); 01042 } 01043 }