CSFunctionWriter.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  1. //
  2. // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Atomic/IO/FileSystem.h>
  23. #include "../JSBind.h"
  24. #include "../JSBModule.h"
  25. #include "../JSBPackage.h"
  26. #include "../JSBEnum.h"
  27. #include "../JSBClass.h"
  28. #include "../JSBFunction.h"
  29. #include "CSTypeHelper.h"
  30. #include "CSFunctionWriter.h"
  31. namespace ToolCore
  32. {
  33. bool CSFunctionWriter::wroteConstructor_ = false;
  34. static bool _CheckNumber(const String& value)
  35. {
  36. // check number initializer
  37. unsigned i;
  38. bool sawDot = false;
  39. for (i = 0; i < value.Length(); i++)
  40. {
  41. char c = value[i];
  42. if (c == '-' && i)
  43. {
  44. break;
  45. }
  46. else if (c == 'f')
  47. {
  48. if (i != value.Length() - 1)
  49. break;
  50. }
  51. else if (c == '.')
  52. {
  53. if (sawDot)
  54. break;
  55. sawDot = true;
  56. }
  57. else if (!isdigit(c))
  58. {
  59. break;
  60. }
  61. }
  62. return i == value.Length();
  63. }
  64. CSFunctionWriter::CSFunctionWriter(JSBFunction *function) : JSBFunctionWriter(function)
  65. {
  66. }
  67. void CSFunctionWriter::WriteNativeParameterMarshal(String& source)
  68. {
  69. }
  70. void CSFunctionWriter::WriteNativeConstructor(String& source)
  71. {
  72. }
  73. void CSFunctionWriter::GenNativeCallParameters(String& sig)
  74. {
  75. JSBClass* klass = function_->GetClass();
  76. const Vector<JSBFunctionType*>& parameters = function_->GetParameters();
  77. Vector<String> args;
  78. unsigned numParams = parameters.Size();
  79. if (function_->HasMutatedReturn())
  80. numParams--;
  81. if (numParams)
  82. {
  83. for (unsigned int i = 0; i < numParams; i++)
  84. {
  85. JSBFunctionType* ptype = parameters.At(i);
  86. // ignore "Context" parameters
  87. if (ptype->type_->asClassType())
  88. {
  89. JSBClassType* classType = ptype->type_->asClassType();
  90. JSBClass* klass = classType->class_;
  91. if (klass->GetName() == "Context")
  92. {
  93. continue;
  94. }
  95. if (klass->IsNumberArray() || ptype->isReference_)
  96. args.Push(ToString("*%s", ptype->name_.CString()));
  97. else
  98. args.Push(ToString("%s", ptype->name_.CString()));
  99. }
  100. else if (ptype->type_->asVectorType())
  101. {
  102. args.Push(ToString("%s__vector", ptype->name_.CString()));
  103. }
  104. else
  105. {
  106. if (ptype->type_->asStringType())
  107. {
  108. args.Push(ToString("%s ? String(%s) : String::EMPTY", ptype->name_.CString(), ptype->name_.CString()));
  109. }
  110. else if (ptype->type_->asStringHashType())
  111. {
  112. args.Push(ToString("StringHash(%s)", ptype->name_.CString()));
  113. }
  114. else
  115. {
  116. args.Push(ToString("%s", ptype->name_.CString()));
  117. }
  118. }
  119. }
  120. }
  121. sig.Join(args, ", ");
  122. }
  123. void CSFunctionWriter::WriteNativeFunction(String& source)
  124. {
  125. JSBClass* klass = function_->GetClass();
  126. JSBPackage* package = klass->GetPackage();
  127. String fname = function_->IsConstructor() ? "Constructor" : function_->GetName();
  128. String returnType;
  129. String functionSig = CSTypeHelper::GetNativeFunctionSignature(function_, returnType);
  130. String line;
  131. line = ToString("ATOMIC_EXPORT_API %s %s\n",
  132. returnType.CString(), functionSig.CString());
  133. source += IndentLine(line);
  134. source += IndentLine("{\n");
  135. Indent();
  136. source += "\n";
  137. if (function_->HasMutatedReturn())
  138. {
  139. line = ToString("if (!__retValue) return;\n");
  140. source += IndentLine(line);
  141. line = ToString("VariantVector __retValueVector;\n");
  142. source += IndentLine(line);
  143. }
  144. // vector marshal
  145. bool hasVectorMarshal = false;
  146. const Vector<JSBFunctionType*>& fparams = function_->GetParameters();
  147. for (unsigned i = 0; i < fparams.Size(); i++)
  148. {
  149. JSBFunctionType* ftype = fparams[i];
  150. // skip mutated input param
  151. if (function_->HasMutatedReturn() && i == fparams.Size() - 1)
  152. break;
  153. // Interface
  154. JSBClass* interface = 0;
  155. if (ftype->type_->asClassType() && ftype->type_->asClassType()->class_->IsInterface())
  156. {
  157. // We need to downcast to the interface
  158. // TODO: this assumes Object* is in hierarchy, how do we validate this?
  159. interface = ftype->type_->asClassType()->class_;
  160. line = ToString("%s = dynamic_cast<%s*>((Object*)%s);\n", ftype->name_.CString(), interface->GetNativeName().CString(), ftype->name_.CString());
  161. source += IndentLine(line);
  162. }
  163. // Vector
  164. JSBVectorType* vtype = ftype->type_->asVectorType();
  165. if (!vtype)
  166. continue;
  167. JSBClassType* classType = vtype->vectorType_->asClassType();
  168. if (!classType)
  169. continue;
  170. String className = classType->class_->GetName();
  171. String vectorMarshal;
  172. hasVectorMarshal = true;
  173. if (vtype->isVariantVector_)
  174. {
  175. const String& pname = ftype->name_;
  176. // TODO: handle early out with return value
  177. if (!function_->returnType_)
  178. source += IndentLine(ToString("if (!%s) return;\n", pname.CString()));
  179. source += IndentLine(ToString("VariantVector %s__vector;\n", pname.CString()));
  180. source += IndentLine(ToString("%s->AdaptToVector(%s__vector);\n", pname.CString(), pname.CString()));
  181. }
  182. else if (vtype->isPODVector_)
  183. {
  184. const String& pname = ftype->name_;
  185. source += IndentLine(ToString("PODVector<%s*> %s__vector;\n", className.CString(), pname.CString()));
  186. source += IndentLine(ToString("if (%s) %s->AdaptToVector<%s*>(%s__vector);\n", pname.CString(), pname.CString(), className.CString(), pname.CString()));
  187. }
  188. else
  189. {
  190. // vectorMarshal = ToString("PODVector<%s*> %s__vector", className.CString(), ftype->name_.CString());
  191. }
  192. if (vectorMarshal.Length())
  193. {
  194. source += IndentLine(vectorMarshal);
  195. vectorMarshal = String::EMPTY;
  196. }
  197. }
  198. bool returnValue = false;
  199. bool sharedPtrReturn = false;
  200. String returnStatement;
  201. if (returnType == "const char*")
  202. {
  203. returnValue = true;
  204. source += IndentLine("static String returnValue;\n");
  205. returnStatement = "returnValue = ";
  206. }
  207. else if (function_->GetReturnClass() && function_->GetReturnClass()->IsNumberArray())
  208. {
  209. returnStatement = "*returnValue = ";
  210. }
  211. else if (function_->GetReturnClass() && function_->GetReturnType()->isSharedPtr_)
  212. {
  213. returnStatement = ToString("SharedPtr<%s> returnValuePtr = ", function_->GetReturnClass()->GetNativeName().CString());
  214. sharedPtrReturn = true;
  215. }
  216. else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
  217. {
  218. // we have an out parameter
  219. JSBVectorType* vtype = function_->GetReturnType()->type_->asVectorType();
  220. if (!vtype->vectorTypeIsSharedPtr_ && !vtype->vectorTypeIsWeakPtr_)
  221. {
  222. returnStatement = ToString("%sVector<%s*> returnValue__vector = ", vtype->isPODVector_ ? "POD" : "", vtype->vectorType_->asClassType()->class_->GetName().CString());
  223. }
  224. else
  225. {
  226. returnStatement = ToString("%sVector<%s<%s>> returnValue__vector = ", vtype->isPODVector_ ? "POD" : "", vtype->vectorTypeIsSharedPtr_ ? "SharedPtr" : "WeakPtr", vtype->vectorType_->asClassType()->class_->GetName().CString());
  227. }
  228. }
  229. else
  230. {
  231. if (returnType != "void" && !hasVectorMarshal)
  232. {
  233. returnStatement = "return ";
  234. }
  235. else if (returnType != "void")
  236. {
  237. returnStatement = ToString("%s returnValue = ", returnType.CString());
  238. }
  239. }
  240. String callSig;
  241. GenNativeCallParameters(callSig);
  242. if (!function_->isConstructor_)
  243. {
  244. if (function_->IsStatic())
  245. {
  246. line = ToString("%s%s::%s(%s);\n", returnStatement.CString(), klass->GetNativeName().CString(), function_->GetName().CString(), callSig.CString());
  247. }
  248. else
  249. {
  250. if (function_->hasMutatedReturn_)
  251. {
  252. // this handles VariantVector case now, can be expanded
  253. line = ToString("__retValueVector = self->%s(%s);\n", function_->GetName().CString(), callSig.CString());
  254. }
  255. else
  256. {
  257. line = ToString("%sself->%s(%s);\n", returnStatement.CString(), function_->GetName().CString(), callSig.CString());
  258. }
  259. }
  260. }
  261. else
  262. {
  263. if (klass->IsAbstract())
  264. {
  265. line = "return 0; // Abstract Class\n";
  266. }
  267. else if (klass->IsObject())
  268. {
  269. if (callSig.Length())
  270. line = ToString("return new %s(NETCore::GetContext(), %s);\n", klass->GetNativeName().CString(), callSig.CString());
  271. else
  272. line = ToString("return new %s(NETCore::GetContext());\n", klass->GetNativeName().CString());
  273. }
  274. else
  275. {
  276. line = ToString("return new %s(%s);\n", klass->GetNativeName().CString(), callSig.CString());
  277. }
  278. }
  279. source += IndentLine(line);
  280. // Vector marshaling
  281. for (unsigned i = 0; i < fparams.Size(); i++)
  282. {
  283. JSBFunctionType* ftype = fparams[i];
  284. JSBVectorType* vtype = ftype->type_->asVectorType();
  285. if (!vtype)
  286. continue;
  287. if (function_->HasMutatedReturn() && i == fparams.Size() - 1)
  288. {
  289. source += IndentLine("__retValue->AdaptFromVector(__retValueVector);\n");
  290. break;
  291. }
  292. JSBClassType* classType = vtype->vectorType_->asClassType();
  293. if (!classType)
  294. continue;
  295. String className = classType->class_->GetName();
  296. String vectorMarshal;
  297. if (vtype->isPODVector_)
  298. {
  299. const String& pname = ftype->name_;
  300. source += IndentLine(ToString("if (%s) %s->AdaptFromVector<%s*>(%s__vector);\n", pname.CString(), pname.CString(), className.CString(), pname.CString()));
  301. }
  302. else
  303. {
  304. // vectorMarshal = ToString("PODVector<%s*> %s__vector", className.CString(), ftype->name_.CString());
  305. }
  306. if (vectorMarshal.Length())
  307. {
  308. source += IndentLine(vectorMarshal);
  309. vectorMarshal = String::EMPTY;
  310. }
  311. }
  312. if (sharedPtrReturn)
  313. {
  314. // We need to keep the shared ptr return value alive through the call, without adding an unwanted reference
  315. source += IndentLine(ToString("%s* returnValue = returnValuePtr;\n", function_->GetReturnClass()->GetNativeName().CString()));
  316. source += IndentLine("if (returnValue)\n");
  317. source += IndentLine("{\n");
  318. Indent();
  319. source += IndentLine("returnValue->AddRefSilent();\n");
  320. source += IndentLine("returnValuePtr = 0;\n");
  321. source += IndentLine("returnValue->ReleaseRefSilent();\n");
  322. Dedent();
  323. source += IndentLine("}\n");
  324. source += IndentLine("return returnValue;\n");
  325. }
  326. else if (returnType == "const char*")
  327. {
  328. source += IndentLine("return returnValue.CString();\n");
  329. }
  330. else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
  331. {
  332. // we have an out parameter
  333. JSBVectorType* vtype = function_->GetReturnType()->type_->asVectorType();
  334. source += IndentLine("if (returnValue) returnValue->AdaptFromVector(returnValue__vector);\n");
  335. }
  336. else if (returnType != "void" && hasVectorMarshal)
  337. {
  338. source += IndentLine("return returnValue;\n");
  339. }
  340. Dedent();
  341. source += IndentLine("}\n");
  342. source += "\n";
  343. }
  344. void CSFunctionWriter::GenerateNativeSource(String& sourceOut)
  345. {
  346. String source = "";
  347. WriteNativeFunction(source);
  348. sourceOut += source;
  349. }
  350. // MANAGED----------------------------------------------------------------------------------------
  351. void CSFunctionWriter::WriteDefaultStructParameters(String& source)
  352. {
  353. for (unsigned i = 0; i < defaultStructParameters_.Size(); i++)
  354. {
  355. const DefaultStructParameter& dparm = defaultStructParameters_[i];
  356. String line = ToString("if (default(%s).Equals(%s)) %s = %s;\n",
  357. dparm.type.CString(), dparm.parameterName.CString(), dparm.parameterName.CString(),
  358. dparm.assignment.CString());
  359. source += IndentLine(line);
  360. }
  361. }
  362. void CSFunctionWriter::WriteManagedPInvokeFunctionSignature(String& source)
  363. {
  364. JSBClass* klass = function_->GetClass();
  365. JSBPackage* package = klass->GetPackage();
  366. if (klass->IsInterface())
  367. return;
  368. source += "\n";
  369. // CoreCLR has pinvoke security demand code commented out, so we do not (currently) need this optimization:
  370. // https://github.com/dotnet/coreclr/issues/1605
  371. // line = "[SuppressUnmanagedCodeSecurity]\n";
  372. // source += IndentLine(line);
  373. String line = "[DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]\n";
  374. source += IndentLine(line);
  375. String returnType = CSTypeHelper::GetPInvokeTypeString(function_->GetReturnType());
  376. // handled by out parameter
  377. if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
  378. returnType = "void";
  379. if (returnType == "bool")
  380. {
  381. // default boolean marshal is 4 byte windows type BOOL and not 1 byte bool
  382. // https://blogs.msdn.microsoft.com/jaredpar/2008/10/14/pinvoke-and-bool-or-should-i-say-bool/
  383. source += IndentLine("[return: MarshalAs(UnmanagedType.I1)]\n");
  384. }
  385. if (returnType == "string")
  386. returnType = "IntPtr";
  387. if (function_->IsConstructor())
  388. returnType = "IntPtr";
  389. const Vector<JSBFunctionType*>& parameters = function_->GetParameters();
  390. Vector<String> args;
  391. if (!function_->IsConstructor() && !function_->IsStatic())
  392. {
  393. args.Push("IntPtr self");
  394. }
  395. if (parameters.Size())
  396. {
  397. for (unsigned int i = 0; i < parameters.Size(); i++)
  398. {
  399. JSBFunctionType* ptype = parameters.At(i);
  400. String name = ptype->name_;
  401. if (name == "object")
  402. name = "_object";
  403. else if (name == "readonly")
  404. name = "readOnly";
  405. else if (name == "params")
  406. name = "parameters";
  407. // ignore "Context" parameters
  408. if (ptype->type_->asClassType())
  409. {
  410. JSBClassType* classType = ptype->type_->asClassType();
  411. JSBClass* klass = classType->class_;
  412. if (klass->GetName() == "Context")
  413. {
  414. continue;
  415. }
  416. if (klass->IsNumberArray())
  417. {
  418. args.Push("ref " + klass->GetName() + " " + name);
  419. }
  420. else
  421. {
  422. args.Push("IntPtr " + name);
  423. }
  424. }
  425. else
  426. {
  427. args.Push(CSTypeHelper::GetPInvokeTypeString(ptype) + " " + name);
  428. }
  429. }
  430. }
  431. if (function_->GetReturnClass())
  432. {
  433. JSBClass* retClass = function_->GetReturnClass();
  434. if (retClass->IsNumberArray())
  435. {
  436. args.Push("ref " + retClass->GetName() + " retValue");
  437. }
  438. }
  439. else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
  440. {
  441. args.Push("IntPtr returnValue");
  442. }
  443. String pstring;
  444. pstring.Join(args, ", ");
  445. String fname = function_->IsConstructor() ? "Constructor" : function_->GetName();
  446. line = ToString("private static extern %s csb_%s_%s_%s_%u(%s);\n",
  447. returnType.CString(), package->GetName().CString(), klass->GetName().CString(),
  448. fname.CString(), function_->GetID(), pstring.CString());
  449. source += IndentLine(line);
  450. source += "\n";
  451. }
  452. void CSFunctionWriter::GenManagedFunctionParameters(String& sig)
  453. {
  454. // generate args
  455. const Vector<JSBFunctionType*>& parameters = function_->GetParameters();
  456. if (parameters.Size())
  457. {
  458. for (unsigned int i = 0; i < parameters.Size(); i++)
  459. {
  460. bool isStruct = false;
  461. JSBFunctionType* ptype = parameters.At(i);
  462. // ignore "Context" parameters
  463. if (ptype->type_->asClassType())
  464. {
  465. JSBClassType* classType = ptype->type_->asClassType();
  466. JSBClass* klass = classType->class_;
  467. if (klass->GetName() == "Context")
  468. {
  469. continue;
  470. }
  471. // TODO: we should have a better system for struct type in general
  472. // This number array is really for JS
  473. if (klass->IsNumberArray())
  474. {
  475. isStruct = true;
  476. }
  477. }
  478. String managedTypeString = CSTypeHelper::GetManagedTypeString(ptype);
  479. String init = ptype->initializer_;
  480. String cast;
  481. String postFix;
  482. if (init.Length())
  483. {
  484. // check any required casts
  485. String type = CSTypeHelper::GetManagedTypeString(ptype->type_);
  486. if (type == "byte" && (function_->class_->GetPackage()->ContainsConstant(init)))
  487. {
  488. cast = "byte";
  489. }
  490. // instead of casting make sure to qualify initializers as float, C# requires a cast/or this
  491. if (type == "float" && _CheckNumber(init) && !init.EndsWith("f"))
  492. {
  493. postFix = "f";
  494. }
  495. }
  496. if (!ptype->isConst_ && (ptype->isReference_ && isStruct))
  497. {
  498. // pass by reference
  499. managedTypeString = "ref " + managedTypeString;
  500. }
  501. sig += managedTypeString;
  502. if (init.Length())
  503. {
  504. init = MapDefaultParameter(ptype);
  505. if (init.Length())
  506. {
  507. if (cast.Length())
  508. sig.AppendWithFormat(" = (%s) %s", cast.CString(), init.CString());
  509. else
  510. sig += " = " + init;
  511. }
  512. sig += postFix;
  513. }
  514. if (i + 1 != parameters.Size())
  515. sig += ", ";
  516. }
  517. }
  518. }
  519. void CSFunctionWriter::WriteManagedConstructor(String& source)
  520. {
  521. JSBClass* klass = function_->GetClass();
  522. JSBPackage* package = klass->GetPackage();
  523. if (klass->GetName() == "RefCounted")
  524. return;
  525. // wrapping constructor
  526. String line;
  527. if (!wroteConstructor_)
  528. {
  529. line = ToString("public %s (IntPtr native) : base (native)\n", klass->GetName().CString());
  530. source += IndentLine(line);
  531. source += IndentLine("{\n");
  532. source += IndentLine("}\n\n");
  533. }
  534. // don't add wrapping constructor for overloads
  535. wroteConstructor_ = true;
  536. String sig;
  537. GenManagedFunctionParameters(sig);
  538. line = ToString("public %s (%s)\n", klass->GetName().CString(), sig.CString());
  539. source += IndentLine(line);
  540. source += IndentLine("{\n");
  541. Indent();
  542. WriteDefaultStructParameters(source);
  543. source += IndentLine("if (nativeInstance == IntPtr.Zero)\n");
  544. source += IndentLine("{\n");
  545. Indent();
  546. source += IndentLine(ToString("var classType = typeof(%s);\n", klass->GetName().CString()));
  547. source += IndentLine("var thisType = this.GetType();\n");
  548. source += IndentLine("var thisTypeIsNative = NativeCore.IsNativeType(thisType);\n");
  549. source += IndentLine("var nativeAncsestorType = NativeCore.GetNativeAncestorType(thisType);\n");
  550. source += IndentLine("if ( (thisTypeIsNative && (thisType == classType)) || (!thisTypeIsNative && (nativeAncsestorType == classType)))\n");
  551. source += IndentLine("{\n");
  552. Indent();
  553. String callSig;
  554. GenPInvokeCallParameters(callSig);
  555. line = ToString("nativeInstance = NativeCore.RegisterNative (csb_%s_%s_Constructor_%u(%s), this);\n",
  556. package->GetName().CString(), klass->GetName().CString(), function_->GetID(), callSig.CString());
  557. source += IndentLine(line);
  558. Dedent();
  559. source += IndentLine("}\n");
  560. Dedent();
  561. source += IndentLine("}\n");
  562. Dedent();
  563. source += IndentLine("}\n");
  564. }
  565. void CSFunctionWriter::GenPInvokeCallParameters(String& sig)
  566. {
  567. // generate args
  568. const Vector<JSBFunctionType*>& parameters = function_->GetParameters();
  569. if (parameters.Size())
  570. {
  571. for (unsigned int i = 0; i < parameters.Size(); i++)
  572. {
  573. JSBFunctionType* ptype = parameters.At(i);
  574. // ignore "Context" parameters
  575. if (ptype->type_->asClassType())
  576. {
  577. JSBClassType* classType = ptype->type_->asClassType();
  578. JSBClass* klass = classType->class_;
  579. if (klass->GetName() == "Context")
  580. {
  581. continue;
  582. }
  583. }
  584. String name = ptype->name_;
  585. if (name == "object")
  586. name = "_object";
  587. else if (name == "readonly")
  588. name = "readOnly";
  589. else if (name == "params")
  590. name = "parameters";
  591. if (ptype->type_->asClassType())
  592. {
  593. JSBClass* pclass = ptype->type_->asClassType()->class_;
  594. if (pclass->IsNumberArray())
  595. {
  596. sig += "ref " + name;
  597. }
  598. else
  599. {
  600. sig += name + " == null ? IntPtr.Zero : " + name + ".NativeInstance";
  601. }
  602. }
  603. else
  604. {
  605. sig += name;
  606. }
  607. if (i + 1 != parameters.Size())
  608. sig += ", ";
  609. }
  610. }
  611. // data marshaller
  612. if (function_->GetReturnType() && !CSTypeHelper::IsSimpleReturn(function_->GetReturnType()))
  613. {
  614. if (function_->GetReturnClass()->IsNumberArray())
  615. {
  616. if (sig.Length())
  617. sig += ", ";
  618. JSBClass* klass = function_->GetClass();
  619. sig += ToString("ref %s%s%uReturnValue", klass->GetName().CString(), function_->GetName().CString(), function_->GetID());
  620. }
  621. }
  622. else if (!function_->IsStatic() && function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
  623. {
  624. if (sig.Length())
  625. sig += ", ";
  626. JSBClass* klass = function_->GetClass();
  627. sig += "returnScriptVector";
  628. }
  629. }
  630. void CSFunctionWriter::WriteManagedFunction(String& source)
  631. {
  632. JSBClass* klass = function_->GetClass();
  633. JSBPackage* package = klass->GetPackage();
  634. String sig;
  635. String returnType = CSTypeHelper::GetManagedTypeString(function_->GetReturnType());
  636. GenManagedFunctionParameters(sig);
  637. String line = klass->IsInterface() ? "" : "public ";
  638. if (function_->IsStatic())
  639. {
  640. line += "static ";
  641. }
  642. bool marked = false;
  643. JSBClass* baseClass = klass->GetBaseClass();
  644. if (baseClass)
  645. {
  646. JSBFunction* override = baseClass->MatchFunction(function_, true);
  647. if (override)
  648. {
  649. marked = true;
  650. if (override->IsVirtual())
  651. line += "override ";
  652. else
  653. line += "new ";
  654. }
  655. }
  656. if (!marked && function_->IsVirtual() && !klass->IsInterface())
  657. line += "virtual ";
  658. line += ToString("%s %s (%s)", returnType.CString(), function_->GetName().CString(), sig.CString());
  659. if (klass->IsInterface())
  660. {
  661. // If we're an interface we have no implementation
  662. line += ";\n\n";
  663. source += IndentLine(line);
  664. return;
  665. }
  666. else
  667. line += "\n";
  668. source += IndentLine(line);
  669. source += IndentLine("{\n");
  670. Indent();
  671. WriteDefaultStructParameters(source);
  672. line.Clear();
  673. if (function_->GetReturnType())
  674. {
  675. if (function_->GetReturnType()->type_->asStringType())
  676. {
  677. line += "return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(";
  678. }
  679. else if (function_->GetReturnType()->type_->asStringHashType())
  680. {
  681. line += "return ";
  682. }
  683. else if (function_->GetReturnType()->type_->asVectorType())
  684. {
  685. JSBVectorType* vtype = function_->GetReturnType()->type_->asVectorType();
  686. String marshalName = ToString("%s%s%uReturnValue", function_->GetClass()->GetName().CString(), function_->GetName().CString(), function_->GetID());
  687. // Defer creation of ScriptVector return value until method is called
  688. if (vtype->vectorType_->asClassType())
  689. {
  690. String classname = vtype->vectorType_->asClassType()->class_->GetName();
  691. source += IndentLine(ToString("if (%s == null) %s = new Vector<%s>();\n", marshalName.CString(), marshalName.CString(), classname.CString()));
  692. }
  693. source += IndentLine(ToString("var returnScriptVector = %s.GetScriptVector();\n", marshalName.CString()));
  694. }
  695. else if (CSTypeHelper::IsSimpleReturn(function_->GetReturnType()))
  696. line += "return ";
  697. else
  698. {
  699. if (function_->GetReturnClass())
  700. {
  701. if (!function_->GetReturnClass()->IsNumberArray())
  702. line += "IntPtr retNativeInstance = ";
  703. }
  704. }
  705. }
  706. String callSig;
  707. GenPInvokeCallParameters(callSig);
  708. String nativeInstance;
  709. if (!function_->IsStatic())
  710. nativeInstance = "nativeInstance";
  711. line += ToString("csb_%s_%s_%s_%u(%s",
  712. package->GetName().CString(), klass->GetName().CString(), function_->GetName().CString(), function_->GetID(), nativeInstance.CString());
  713. if (callSig.Length())
  714. {
  715. if (nativeInstance.Length())
  716. line += ", " + callSig;
  717. else
  718. line += callSig;
  719. }
  720. if (function_->GetReturnType())
  721. {
  722. if (function_->GetReturnType()->type_->asStringType())
  723. line += ")";
  724. }
  725. line += ");\n";
  726. source += IndentLine(line);
  727. if (function_->GetReturnType() && !CSTypeHelper::IsSimpleReturn(function_->GetReturnType()))
  728. {
  729. if (function_->GetReturnType()->type_->asClassType())
  730. {
  731. JSBClass* retClass = function_->GetReturnClass();
  732. JSBClass* klass = function_->GetClass();
  733. if (retClass->IsNumberArray())
  734. {
  735. line = ToString("return %s%s%uReturnValue;", klass->GetName().CString(), function_->GetName().CString(), function_->GetID());
  736. }
  737. else
  738. {
  739. line = ToString("return retNativeInstance == IntPtr.Zero ? null : NativeCore.WrapNative<%s> (retNativeInstance);", retClass->GetName().CString());
  740. }
  741. source += IndentLine(line);
  742. source+= "\n";
  743. }
  744. }
  745. else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
  746. {
  747. if (!function_->IsStatic())
  748. {
  749. source += IndentLine(ToString("return %s%s%uReturnValue;", klass->GetName().CString(), function_->GetName().CString(), function_->GetID()));
  750. source+= "\n";
  751. }
  752. }
  753. Dedent();
  754. source += IndentLine("}\n");
  755. }
  756. void CSFunctionWriter::GenerateManagedSource(String& sourceOut)
  757. {
  758. JSBClass* klass = function_->GetClass();
  759. String source = "";
  760. Indent();
  761. Indent();
  762. if (function_->GetDocString().Length())
  763. {
  764. // monodocer -assembly:NETCore.dll -path:en -pretty
  765. // mdoc export-html -o htmldocs en
  766. source += IndentLine("/// <summary>\n");
  767. if (function_->GetDocString().Contains('\n'))
  768. source += IndentLine("/* " + function_->GetDocString() + "*/\n");
  769. else
  770. source += IndentLine("/// " + function_->GetDocString() + "\n");
  771. source += IndentLine("/// </summary>\n");
  772. }
  773. if (function_->IsConstructor())
  774. WriteManagedConstructor(source);
  775. else
  776. WriteManagedFunction(source);
  777. WriteManagedPInvokeFunctionSignature(source);
  778. if (!klass->IsInterface())
  779. {
  780. // data marshaller
  781. if (function_->GetReturnType() && !CSTypeHelper::IsSimpleReturn(function_->GetReturnType()))
  782. {
  783. if (function_->GetReturnClass())
  784. {
  785. JSBClass* retClass = function_->GetReturnClass();
  786. if (retClass->IsNumberArray())
  787. {
  788. String managedType = CSTypeHelper::GetManagedTypeString(function_->GetReturnType());
  789. String marshal = "private ";
  790. if (function_->IsStatic())
  791. marshal += "static ";
  792. marshal += managedType + " ";
  793. marshal += ToString("%s%s%uReturnValue;\n", klass->GetName().CString(), function_->GetName().CString(), function_->GetID());
  794. sourceOut += IndentLine(marshal);
  795. }
  796. }
  797. }
  798. else if (!function_->IsStatic() && function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
  799. {
  800. JSBVectorType* vtype = function_->GetReturnType()->type_->asVectorType();
  801. if (vtype->vectorType_->asClassType())
  802. {
  803. String classname = vtype->vectorType_->asClassType()->class_->GetName();
  804. String typestring = "Vector<" + classname + ">";
  805. String marshal = "private " + typestring + " ";
  806. marshal += ToString("%s%s%uReturnValue = null;\n", function_->GetClass()->GetName().CString(), function_->GetName().CString(), function_->GetID());
  807. sourceOut += IndentLine(marshal);
  808. }
  809. }
  810. }
  811. Dedent();
  812. Dedent();
  813. sourceOut += source;
  814. }
  815. void CSFunctionWriter::GenerateSource(String& sourceOut)
  816. {
  817. }
  818. String CSFunctionWriter::MapDefaultParameter(JSBFunctionType* parameter)
  819. {
  820. String init = parameter->initializer_;
  821. if (!init.Length())
  822. return init;
  823. if (parameter->type_->asClassType())
  824. {
  825. if (init == "0")
  826. return "null";
  827. }
  828. if (parameter->type_->asEnumType())
  829. {
  830. return parameter->type_->asEnumType()->enum_->GetName() + "." + init;
  831. }
  832. if (function_->class_->GetPackage()->ContainsConstant(init))
  833. return "Constants." + init;
  834. if (init == "true" || init == "false")
  835. return init;
  836. if (_CheckNumber(init))
  837. return init;
  838. if (init == "\"\\t\"")
  839. return init;
  840. if (init == "NULL")
  841. return "null";
  842. if (init == "M_MAX_UNSIGNED")
  843. return "0xffffffff";
  844. if (init == "String::EMPTY")
  845. return "\"\"";
  846. // this kind of sucks, can't define const structs
  847. // and default parameters need to be const :/
  848. DefaultStructParameter dparm;
  849. dparm.parameterName = parameter->name_;
  850. if (init == "Vector3::ZERO")
  851. {
  852. dparm.type = "Vector3";
  853. dparm.assignment = "Vector3.Zero";
  854. defaultStructParameters_.Push(dparm);
  855. return "default(Vector3)";
  856. }
  857. if (init == "Vector3::ONE")
  858. {
  859. dparm.type = "Vector3";
  860. dparm.assignment = "Vector3.One";
  861. defaultStructParameters_.Push(dparm);
  862. return "default(Vector3)";
  863. }
  864. if (init == "Vector3::UP")
  865. {
  866. dparm.type = "Vector3";
  867. dparm.assignment = "Vector3.Up";
  868. defaultStructParameters_.Push(dparm);
  869. return "default(Vector3)";
  870. }
  871. if (init == "IntVector2::ZERO")
  872. {
  873. dparm.type = "IntVector2";
  874. dparm.assignment = "IntVector2.Zero";
  875. defaultStructParameters_.Push(dparm);
  876. return "default(IntVector2)";
  877. }
  878. if (init == "Quaternion::IDENTITY")
  879. {
  880. dparm.type = "Quaternion";
  881. dparm.assignment = "Quaternion.Identity";
  882. defaultStructParameters_.Push(dparm);
  883. return "default(Quaternion)";
  884. }
  885. if (init == "StringHash::ZERO")
  886. {
  887. dparm.type = "StringHash";
  888. dparm.assignment = "StringHash.Zero";
  889. defaultStructParameters_.Push(dparm);
  890. return "default(StringHash)";
  891. }
  892. return String::EMPTY;
  893. }
  894. }