JSBClass.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  2. // Please see LICENSE.md in repository root for license information
  3. // https://github.com/AtomicGameEngine/AtomicGameEngine
  4. #include <Atomic/Atomic.h>
  5. #include <Atomic/IO/Log.h>
  6. #include <Atomic/Core/ProcessUtils.h>
  7. #include "JSBClass.h"
  8. #include "JSBFunction.h"
  9. #include "JSBModule.h"
  10. #include "JSBind.h"
  11. Vector<JSBClass*> JSBClass::allClasses_;
  12. JSBFunctionOverride::JSBFunctionOverride(const String &name, const Vector<String>& sig) : parsed_(false)
  13. {
  14. name_ = name;
  15. sig_ = sig;
  16. }
  17. void JSBFunctionOverride::Parse()
  18. {
  19. if (parsed_)
  20. return;
  21. parsed_ = true;
  22. for (unsigned i = 0; i < sig_.Size(); i++)
  23. {
  24. JSBType* type = JSBType::Parse(sig_.At(i));
  25. if (!type)
  26. {
  27. ErrorExit("Unable to parse override type");
  28. }
  29. types_.Push(type);
  30. }
  31. }
  32. void JSBEnum::Preprocess()
  33. {
  34. // TextureUnit is a special case as uses preprocessor for values depending on
  35. // Desktop or Mobile graphics
  36. if (name_ == "TextureUnit")
  37. {
  38. values_.Clear();
  39. values_.Push("TU_DIFFUSE");
  40. values_.Push("TU_ALBEDOBUFFER");
  41. values_.Push("TU_NORMAL");
  42. values_.Push("TU_NORMALBUFFER");
  43. values_.Push("TU_SPECULAR");
  44. values_.Push("TU_EMISSIVE");
  45. values_.Push("TU_ENVIRONMENT");
  46. bool mobile = JSBind::PLATFORM == "WEB" || JSBind::PLATFORM == "ANDROID" || JSBind::PLATFORM == "IOS";
  47. if (mobile)
  48. {
  49. values_.Push("TU_LIGHTRAMP");
  50. values_.Push("TU_LIGHTSHAPE");
  51. values_.Push("TU_SHADOWMAP");
  52. values_.Push("MAX_MATERIAL_TEXTURE_UNITS");
  53. values_.Push("MAX_TEXTURE_UNITS");
  54. }
  55. else
  56. {
  57. values_.Push("TU_VOLUMEMAP");
  58. values_.Push("TU_CUSTOM1");
  59. values_.Push("TU_CUSTOM2");
  60. values_.Push("TU_LIGHTRAMP");
  61. values_.Push("TU_LIGHTSHAPE");
  62. values_.Push("TU_SHADOWMAP");
  63. values_.Push("TU_FACESELECT");
  64. values_.Push("TU_INDIRECTION");
  65. values_.Push("TU_DEPTHBUFFER");
  66. values_.Push("TU_LIGHTBUFFER");
  67. values_.Push("TU_ZONE");
  68. values_.Push("MAX_MATERIAL_TEXTURE_UNITS");
  69. values_.Push("MAX_TEXTURE_UNITS");
  70. }
  71. }
  72. }
  73. void JSBClass::WriteForwardDeclarations(String& source)
  74. {
  75. if (isNumberArray())
  76. return;
  77. source.AppendWithFormat("static duk_ret_t jsb_constructor_%s(duk_context* ctx);\n", GetName().CString());
  78. source.AppendWithFormat("static void jsb_class_define_%s(JSVM* vm);\n", GetName().CString());
  79. }
  80. void JSBClass::WriteFunctions(String& source)
  81. {
  82. for (unsigned i = 0; i < functions_.Size(); i++)
  83. {
  84. JSBFunction* function = functions_.At(i);
  85. if (function->Skip())
  86. continue;
  87. if (function->isDestructor_)
  88. continue;
  89. functions_.At(i)->Write(source);
  90. }
  91. }
  92. void JSBClass::WriteDefinition(String& source)
  93. {
  94. if (isNumberArray())
  95. return;
  96. WriteFunctions(source);
  97. source.AppendWithFormat("static void jsb_class_define_%s(JSVM* vm)\n{\n", GetName().CString());
  98. source.Append("duk_context* ctx = vm->GetJSContext();\n");
  99. source.AppendWithFormat("js_class_get_prototype(ctx, \"%s\");\n", GetName().CString());
  100. for (unsigned i = 0; i < functions_.Size(); i++)
  101. {
  102. JSBFunction* function = functions_.At(i);
  103. if (function->Skip())
  104. continue;
  105. if (function->isConstructor_ || function->isDestructor_)
  106. continue;
  107. if (function->FirstDefaultParameter() != -1)
  108. {
  109. source.AppendWithFormat("duk_push_c_function(ctx, jsb_class_%s_%s, DUK_VARARGS);\n", GetName().CString(), function->name_.CString());
  110. }
  111. else
  112. {
  113. source.AppendWithFormat("duk_push_c_function(ctx, jsb_class_%s_%s, %i);\n", GetName().CString(), function->name_.CString(), (int) function->parameters_.Size());
  114. }
  115. String scriptName = function->name_;
  116. scriptName[0] = tolower(scriptName[0]);
  117. source.AppendWithFormat("duk_put_prop_string(ctx, -2, \"%s\");\n", scriptName.CString());
  118. }
  119. source.Append("duk_pop(ctx);\n");
  120. source.Append("}\n");
  121. }
  122. void JSBClass::Write(String& source)
  123. {
  124. WriteDefinition(source);
  125. }
  126. void JSBClass::AddFunction(JSBFunction* function)
  127. {
  128. functions_.Push(function);
  129. }
  130. void JSBClass::AddFunctionOverride(JSBFunctionOverride* functionOverride)
  131. {
  132. overrides_.Push(functionOverride);
  133. }
  134. void JSBClass::Dump()
  135. {
  136. if (name_ != className_)
  137. {
  138. LOGINFOF("Class: %s (%s)", name_.CString(), className_.CString());
  139. }
  140. else
  141. {
  142. LOGINFOF("Class: %s", name_.CString());
  143. }
  144. LOGINFOF(" IsObject: %s", isObject() ? "true" : "false");
  145. if (baseClasses_.Size())
  146. {
  147. LOGINFOF(" Bases:");
  148. for (unsigned i = 0; i < baseClasses_.Size(); i++)
  149. {
  150. LOGINFOF(" %s", baseClasses_.At(i)->GetClassName().CString());
  151. }
  152. }
  153. if (functions_.Size())
  154. {
  155. for (unsigned i = 0; i < functions_.Size(); i++)
  156. {
  157. functions_.At(i)->Dump();
  158. }
  159. }
  160. }
  161. void JSBClass::WriteProtoTypeRecursive(String &source, JSBClass* klass, Vector<JSBClass*>& written)
  162. {
  163. if (written.Contains(klass))
  164. return;
  165. Vector<JSBClass*>::Iterator itr = klass->baseClasses_.End() - 1 ;
  166. while (itr != klass->baseClasses_.Begin() - 1)
  167. {
  168. WriteProtoTypeRecursive(source, (*itr), written);
  169. itr--;
  170. }
  171. JSBClass* base = klass->baseClasses_.Size() ? klass->baseClasses_[0] : NULL;
  172. if (!klass->isNumberArray())
  173. {
  174. JSBModule* module = klass->GetModule();
  175. if (module->Requires("3D"))
  176. source += "\n#ifdef ATOMIC_3D\n";
  177. source.AppendWithFormat(" js_setup_prototype(vm, \"%s\", \"%s\", %s);\n",
  178. klass->GetName().CString(), base ? base->GetName().CString() : "",
  179. klass->hasProperties() ? "true" : "false");
  180. if (module->Requires("3D"))
  181. source += "#endif\n\n";
  182. }
  183. written.Push(klass);
  184. }
  185. void JSBClass::WriteProtoTypeSetup(String& source)
  186. {
  187. Vector<JSBClass*> written;
  188. for (unsigned i = 0; i < allClasses_.Size(); i++)
  189. {
  190. JSBClass* klass = allClasses_.At(i);
  191. WriteProtoTypeRecursive(source, klass, written);
  192. }
  193. }
  194. void JSBClass::AddPropertyFunction(JSBFunction* function)
  195. {
  196. hasProperties_ = true;
  197. if (!function->propertyName_.Length())
  198. {
  199. ErrorExit("Function has no property name");
  200. }
  201. if (!function->isGetter_ && !function->isSetter_)
  202. {
  203. ErrorExit("Function is not a getter or setter");
  204. }
  205. JSBProperty* prop = NULL;
  206. if (properties_.Contains(function->propertyName_))
  207. {
  208. prop = properties_[function->propertyName_];
  209. }
  210. if (!prop)
  211. {
  212. prop = new JSBProperty();
  213. properties_[function->propertyName_] = prop;
  214. }
  215. if (prop->getter_ && function->isGetter_)
  216. {
  217. ErrorExit("getter already registered");
  218. }
  219. if (prop->setter_ && function->isSetter_)
  220. {
  221. ErrorExit("setter already registered");
  222. }
  223. if (function->isSetter_)
  224. prop->setter_ = function;
  225. else
  226. prop->getter_ = function;
  227. }
  228. void JSBClass::SetSkipFunction(const String& name, bool skip)
  229. {
  230. for (unsigned i = 0; i < functions_.Size(); i++)
  231. {
  232. if (functions_[i]->isConstructor_)
  233. continue;
  234. if (functions_[i]->name_ == name)
  235. functions_[i]->SetSkip(skip);
  236. }
  237. }
  238. JSBFunction* JSBClass::GetFunction(const String& name)
  239. {
  240. for (unsigned i = 0; i < functions_.Size(); i++)
  241. {
  242. if (functions_[i]->name_ == name)
  243. return functions_[i];
  244. }
  245. return 0;
  246. }
  247. void JSBClass::Process()
  248. {
  249. for (unsigned i = 0; i < allClasses_.Size(); i++)
  250. {
  251. JSBClass* klass = allClasses_[i];
  252. for (unsigned j = 0; j < klass->overrides_.Size(); j++)
  253. {
  254. klass->overrides_.At(j)->Parse();
  255. }
  256. // detect overridden functions, only works for in class atm (not baseclasses)
  257. for (unsigned j = 0; j < klass->functions_.Size(); j++)
  258. {
  259. JSBFunction* function = klass->functions_[j];
  260. if (klass->isNumberArray())
  261. {
  262. function->SetSkip(true);
  263. continue;
  264. }
  265. // skip function if only one parameter of type Context, if not Constuctor
  266. if (!function->isConstructor_)
  267. if (function->parameters_.Size() == 1 && function->parameters_.At(0)->type_->asClassType())
  268. {
  269. if (function->parameters_.At(0)->type_->asClassType()->class_->GetClassName() == "Context")
  270. {
  271. function->SetSkip(true);
  272. continue;
  273. }
  274. }
  275. if (function->isOverride_)
  276. continue;
  277. for (unsigned k = 0; k < klass->functions_.Size(); k++)
  278. {
  279. if (j == k)
  280. continue;
  281. JSBFunction* function2 = klass->functions_[k];
  282. if (function->name_ == function2->name_)
  283. {
  284. function->isOverride_ = true;
  285. function2->isOverride_ = true;
  286. // initially set all overridden functions to skip
  287. function->SetSkip(true);
  288. function2->SetSkip(true);
  289. break;
  290. }
  291. }
  292. }
  293. // mark overrides
  294. for (unsigned j = 0; j < klass->functions_.Size(); j++)
  295. {
  296. JSBFunction* function = klass->functions_[j];
  297. if (function->isOverride_)
  298. {
  299. for (unsigned k = 0; k < klass->overrides_.Size(); k++)
  300. {
  301. JSBFunctionOverride* override = klass->overrides_[k];
  302. if (override->name_ != function->name_)
  303. continue;
  304. if (override->types_.Size() != function->parameters_.Size())
  305. continue;
  306. bool match = true;
  307. for (unsigned x = 0; x < function->parameters_.Size(); x++)
  308. {
  309. JSBType* ot = override->types_[x];
  310. JSBType* pt = function->parameters_[x]->type_;
  311. // should add an == operator
  312. if ((ot->asPrimitiveType() == NULL) != (pt->asPrimitiveType() == NULL) ||
  313. (ot->asClassType() == NULL) != (pt->asClassType() == NULL) )
  314. {
  315. match = false;
  316. break;
  317. }
  318. if (ot->asPrimitiveType())
  319. {
  320. JSBPrimitiveType* pot = ot->asPrimitiveType();
  321. JSBPrimitiveType* ppt = pt->asPrimitiveType();
  322. if (pot->kind_ != ppt->kind_)
  323. {
  324. match = false;
  325. break;
  326. }
  327. }
  328. if (ot->asClassType())
  329. {
  330. JSBClassType* cot = ot->asClassType();
  331. JSBClassType* cpt = pt->asClassType();
  332. if (cot->class_ != cpt->class_)
  333. {
  334. match = false;
  335. break;
  336. }
  337. }
  338. if (ot->asStringType())
  339. {
  340. if (!pt->asStringType())
  341. {
  342. match = false;
  343. break;
  344. }
  345. }
  346. if (ot->asStringHashType())
  347. {
  348. if (!pt->asStringHashType())
  349. {
  350. match = false;
  351. break;
  352. }
  353. }
  354. }
  355. if (match)
  356. {
  357. function->SetSkip(false);
  358. break;
  359. }
  360. }
  361. }
  362. }
  363. }
  364. for (unsigned i = 0; i < allClasses_.Size(); i++)
  365. {
  366. JSBClass* klass = allClasses_[i];
  367. for (unsigned j = 0; j < klass->functions_.Size(); j++)
  368. {
  369. JSBFunction* function = klass->functions_[j];
  370. function->Process();
  371. }
  372. }
  373. }
  374. JSBFunction* JSBClass::GetConstructor()
  375. {
  376. {
  377. for (unsigned i = 0; i < functions_.Size(); i++)
  378. if (functions_[i]->isConstructor_ && !functions_[i]->Skip())
  379. return functions_[i];
  380. }
  381. return NULL;
  382. }
  383. void JSBClass::Preprocess()
  384. {
  385. for (unsigned i = 0; i < allClasses_.Size(); i++)
  386. {
  387. JSBClass* klass = allClasses_[i];
  388. RecursiveAddBaseClass(klass, klass->baseClasses_);
  389. }
  390. for (unsigned i = 0; i < allClasses_.Size(); i++)
  391. {
  392. JSBClass* klass = allClasses_[i];
  393. if (klass->GetClassName() == "Object")
  394. klass->setObject(true);
  395. for (unsigned j = 0; j < klass->baseClasses_.Size(); j++)
  396. {
  397. if (klass->baseClasses_[j]->GetClassName() == "Object")
  398. klass->setObject(true);
  399. }
  400. }
  401. }