create_wrapper.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. #include <config.h>
  2. #include "tree.hpp"
  3. #include "create_wrapper.hpp"
  4. #include "globals.hpp"
  5. #include <iostream>
  6. #include <sstream>
  7. #include <stdexcept>
  8. #include <stdio.h>
  9. void
  10. WrapperCreator::create_wrapper(Namespace* ns)
  11. {
  12. std::string fromfile = original_file != "" ? original_file : inputfile;
  13. if(selected_namespace != "") {
  14. ns_prefix = selected_namespace;
  15. ns_prefix += "::";
  16. }
  17. // hpp file
  18. hppout
  19. << "/**\n"
  20. << " * WARNING: This file is automatically generated from:\n"
  21. << " * '" << fromfile << "'\n"
  22. << " * DO NOT CHANGE\n"
  23. << " */\n"
  24. << "#ifndef HEADER_SUPERTUX_SCRIPTING_WRAPPER_HPP\n" //TODO avoid hardcoding
  25. << "#define HEADER_SUPERTUX_SCRIPTING_WRAPPER_HPP\n"
  26. << "\n"
  27. << "#include <squirrel.h>\n"
  28. << "\n"
  29. << "namespace scripting {\n"
  30. << "\n";
  31. hppout << "void register_" << modulename << "_wrapper(HSQUIRRELVM v);\n"
  32. << "\n";
  33. for(auto& type : ns->types) {
  34. auto _class = dynamic_cast<Class*> (type);
  35. if(_class == 0)
  36. continue;
  37. hppout << "class " << _class->name << ";\n";
  38. hppout << "void create_squirrel_instance(HSQUIRRELVM v, "
  39. << ns_prefix << _class->name
  40. << "* object, bool setup_releasehook = false);\n";
  41. }
  42. hppout <<"\n"
  43. << "}\n"
  44. << "\n"
  45. << "#endif\n"
  46. << "\n"
  47. << "/* EOF */\n";
  48. // cpp header
  49. out << "/**\n"
  50. << " * WARNING: This file is automatically generated from:\n"
  51. << " * '" << fromfile << "'\n"
  52. << " * DO NOT CHANGE\n"
  53. << " */\n"
  54. << "\n"
  55. << "#include \"scripting/wrapper.hpp\"\n"
  56. << "\n"
  57. << "#include <assert.h>\n"
  58. << "#include <limits>\n"
  59. << "#include <sstream>\n"
  60. << "\n"
  61. << "#include \"squirrel/squirrel_error.hpp\"\n"
  62. << "#include \"scripting/wrapper.interface.hpp\"\n"
  63. << "\n"
  64. << "namespace scripting {\n"
  65. << "namespace wrapper {\n"
  66. << "\n";
  67. for(auto& type : ns->types) {
  68. auto _class = dynamic_cast<Class*> (type);
  69. if(_class != 0)
  70. create_class_wrapper(_class);
  71. }
  72. for(auto& func : ns->functions) {
  73. create_function_wrapper(0, func);
  74. }
  75. out << "} // namespace wrapper\n";
  76. for(auto& type : ns->types) {
  77. Class* _class = dynamic_cast<Class*> (type);
  78. if(_class != 0)
  79. create_squirrel_instance(_class);
  80. }
  81. out << "void register_" << modulename << "_wrapper(HSQUIRRELVM v)\n"
  82. << "{\n"
  83. << ind << "using namespace wrapper;\n"
  84. << "\n";
  85. create_register_constants_code(ns);
  86. create_register_functions_code(ns);
  87. create_register_classes_code(ns);
  88. out << "}\n"
  89. << "\n"
  90. << "} // namespace scripting\n"
  91. << "\n"
  92. << "/* EOF */\n";
  93. }
  94. void
  95. WrapperCreator::create_register_function_code(Function* function, Class* _class)
  96. {
  97. if(function->type == Function::DESTRUCTOR)
  98. return;
  99. out << ind << "sq_pushstring(v, \"" << function->name << "\", -1);\n";
  100. out << ind << "sq_newclosure(v, &"
  101. << (_class != 0 ? _class->name + "_" : "") << function->name
  102. << "_wrapper, 0);\n";
  103. if(function->custom) {
  104. out << ind << "sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, " << function->parameter_spec << ");\n";
  105. } else {
  106. out << ind << "sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, \"";
  107. out << "x|t";
  108. if(!function->parameters.empty())
  109. {
  110. std::vector<Parameter>::iterator p = function->parameters.begin();
  111. // Skip the first parameter since its a HSQUIRRELVM that is
  112. // handled internally
  113. if (function->suspend) {
  114. ++p;
  115. } else if (p->type.atomic_type == HSQUIRRELVMType::instance()) {
  116. ++p;
  117. }
  118. for(; p != function->parameters.end(); ++p) {
  119. if(p->type.atomic_type == &BasicType::INT) {
  120. out << "i";
  121. } else if(p->type.atomic_type == &BasicType::FLOAT) {
  122. out << "n";
  123. } else if(p->type.atomic_type == &BasicType::BOOL) {
  124. out << "b";
  125. } else if(p->type.atomic_type == StringType::instance()) {
  126. out << "s";
  127. } else {
  128. out << ".";
  129. }
  130. }
  131. }
  132. out << "\");\n";
  133. }
  134. create_register_slot_code("function", function->name);
  135. out << "\n";
  136. }
  137. void
  138. WrapperCreator::create_register_functions_code(Namespace* ns)
  139. {
  140. for(auto& function : ns->functions) {
  141. create_register_function_code(function, 0);
  142. }
  143. }
  144. void
  145. WrapperCreator::create_register_classes_code(Namespace* ns)
  146. {
  147. for(auto& type : ns->types) {
  148. auto _class = dynamic_cast<Class*> (type);
  149. if(_class == 0)
  150. continue;
  151. if(_class->super_classes.size() > 0)
  152. continue;
  153. create_register_class_code(_class);
  154. }
  155. }
  156. void
  157. WrapperCreator::create_register_class_code(Class* _class)
  158. {
  159. out << ind << "// Register class " << _class->name << "\n";
  160. out << ind << "sq_pushstring(v, \""
  161. << _class->name << "\", -1);\n";
  162. if(_class->super_classes.size() > 0) {
  163. if(_class->super_classes.size() > 1) {
  164. std::ostringstream msg;
  165. msg << "Multiple inheritance not supported (at class '"
  166. << _class->name << "')";
  167. throw std::runtime_error(msg.str());
  168. }
  169. out << ind << "sq_pushstring(v, \""
  170. << _class->super_classes[0]->name << "\", -1);\n";
  171. out << ind << "sq_get(v, -3);\n";
  172. }
  173. out << ind << "if(sq_newclass(v, "
  174. << (_class->super_classes.size() > 0 ? "SQTrue" : "SQFalse")
  175. << ") < 0) {\n";
  176. out << ind << ind << "std::ostringstream msg;\n";
  177. out << ind << ind << "msg << \"Couldn't create new class '"
  178. << _class->name << "'\";\n";
  179. out << ind << ind << "throw SquirrelError(v, msg.str());\n";
  180. out << ind << "}\n";
  181. for(auto& member : _class->members) {
  182. if(member->visibility != ClassMember::PUBLIC)
  183. continue;
  184. auto function = dynamic_cast<Function*> (member);
  185. if(function) {
  186. create_register_function_code(function, _class);
  187. }
  188. auto field = dynamic_cast<Field*> (member);
  189. if(field) {
  190. create_register_constant_code(field);
  191. }
  192. }
  193. create_register_slot_code("class", _class->name);
  194. out << "\n";
  195. for(auto& c : _class->sub_classes) {
  196. create_register_class_code(c);
  197. }
  198. }
  199. void
  200. WrapperCreator::create_register_constants_code(Namespace* ns)
  201. {
  202. for(auto& field: ns->fields) {
  203. create_register_constant_code(field);
  204. }
  205. }
  206. void
  207. WrapperCreator::create_register_constant_code(Field* field)
  208. {
  209. if(!field->has_const_value)
  210. return;
  211. out << ind << "sq_pushstring(v, \"" << field->name << "\", -1);\n";
  212. if(field->type->atomic_type == &BasicType::INT) {
  213. out << ind << "sq_pushinteger(v, " << field->const_int_value << ");\n";
  214. } else if(field->type->atomic_type == &BasicType::FLOAT) {
  215. out << ind << "sq_pushfloat(v, " << field->const_float_value << ");\n";
  216. } else if(field->type->atomic_type == StringType::instance()) {
  217. out << ind << "sq_pushstring(v, \""
  218. << field->const_string_value << "\", -1);\n";
  219. } else {
  220. throw std::runtime_error("Constant is not int, float or string");
  221. }
  222. create_register_slot_code("constant", field->name);
  223. out << "\n";
  224. }
  225. void
  226. WrapperCreator::create_register_slot_code(const std::string& what,
  227. const std::string& name)
  228. {
  229. out << ind << "if(SQ_FAILED(sq_createslot(v, -3))) {\n";
  230. out << ind << ind << "throw SquirrelError(v, \""
  231. << "Couldn't register " << what << " '" << name << "'\");\n";
  232. out << ind << "}\n";
  233. }
  234. void
  235. WrapperCreator::create_function_wrapper(Class* _class, Function* function)
  236. {
  237. if(function->type == Function::DESTRUCTOR)
  238. assert(false);
  239. std::string ns_prefix;
  240. if(selected_namespace != "")
  241. ns_prefix = selected_namespace + "::";
  242. if(function->type == Function::CONSTRUCTOR)
  243. function->name = "constructor";
  244. out << "static SQInteger ";
  245. if(_class != 0) {
  246. out << _class->name << "_";
  247. }
  248. out << function->name << "_wrapper(HSQUIRRELVM vm)\n"
  249. << "{\n";
  250. // avoid warning...
  251. if(_class == 0 && function->parameters.empty()
  252. && function->return_type.is_void()
  253. && function->type != Function::CONSTRUCTOR) {
  254. out << ind << "(void) vm;\n";
  255. }
  256. // retrieve pointer to class instance
  257. if(_class != 0 && function->type != Function::CONSTRUCTOR) {
  258. out << ind << "SQUserPointer data;\n";
  259. out << ind << "if(SQ_FAILED(sq_getinstanceup(vm, 1, &data, nullptr)) || !data) {\n";
  260. out << ind << ind << "sq_throwerror(vm, _SC(\"'" << function->name << "' called without instance\"));\n";
  261. out << ind << ind << "return SQ_ERROR;\n";
  262. out << ind << "}\n";
  263. out << ind << "auto _this = reinterpret_cast<" << ns_prefix << _class->name << "*> (data);\n";
  264. out << "\n";
  265. out << ind << "if (_this == nullptr) {\n";
  266. out << ind << ind << "return SQ_ERROR;\n";
  267. out << ind << "}\n";
  268. out << "\n";
  269. }
  270. // custom function?
  271. if(function->custom) {
  272. if(function->type != Function::FUNCTION)
  273. throw std::runtime_error(
  274. "custom not allow constructor+destructor yet");
  275. if(function->return_type.atomic_type != SQIntegerType::instance())
  276. throw std::runtime_error("custom function '" + function->name + "' has to return SQInteger");
  277. if(function->parameters.size() != 1)
  278. throw std::runtime_error(
  279. "custom function '" + function->name + "' must have 1 HSQUIRRELVM parameter");
  280. out << ind << "return ";
  281. if(_class != 0)
  282. out << "_this->";
  283. else
  284. out << ns_prefix;
  285. out << function->name << "(vm);\n";
  286. out << "}\n";
  287. out << "\n";
  288. return;
  289. }
  290. // declare and retrieve arguments
  291. int i = 0;
  292. int arg_offset = 2;
  293. for(auto& p : function->parameters) {
  294. if(i == 0 && p.type.atomic_type == HSQUIRRELVMType::instance()) {
  295. out << ind << "HSQUIRRELVM arg0 = vm;\n";
  296. arg_offset--;
  297. } else {
  298. char argname[64];
  299. snprintf(argname, sizeof(argname), "arg%d", i);
  300. prepare_argument(p.type, i + arg_offset, argname);
  301. }
  302. ++i;
  303. }
  304. // call function
  305. out << "\n";
  306. out << ind << "try {\n";
  307. out << ind << ind;
  308. if(!function->return_type.is_void()) {
  309. function->return_type.write_c_type(out);
  310. out << " return_value = ";
  311. }
  312. if(_class != 0) {
  313. if(function->type == Function::CONSTRUCTOR) {
  314. out << "auto _this = new " << ns_prefix;
  315. } else {
  316. out << "_this->";
  317. }
  318. } else {
  319. out << ns_prefix;
  320. }
  321. if(function->type == Function::CONSTRUCTOR) {
  322. out << _class->name << "(";
  323. } else {
  324. out << function->name << "(";
  325. }
  326. for(size_t i = 0; i < function->parameters.size(); ++i) {
  327. if(i != 0)
  328. out << ", ";
  329. const Parameter param = function->parameters[i];
  330. if(param.type.ref == 0 && param.type.pointer == 0) {
  331. if(param.type.atomic_type == &BasicType::INT)
  332. out << "static_cast<int> (arg" << i << ")";
  333. else if(param.type.atomic_type == &BasicType::FLOAT)
  334. out << "static_cast<float> (arg" << i << ")";
  335. else if(param.type.atomic_type == &BasicType::BOOL)
  336. out << "arg" << i << " == SQTrue";
  337. else
  338. out << "arg" << i;
  339. } else {
  340. out << "arg" << i;
  341. }
  342. }
  343. out << ");\n";
  344. if(function->type == Function::CONSTRUCTOR) {
  345. out << ind << "if(SQ_FAILED(sq_setinstanceup(vm, 1, _this))) {\n";
  346. out << ind << ind << "sq_throwerror(vm, _SC(\"Couldn't setup instance of '" << _class->name << "' class\"));\n";
  347. out << ind << ind << "return SQ_ERROR;\n";
  348. out << ind << "}\n";
  349. out << ind << "sq_setreleasehook(vm, 1, "
  350. << _class->name << "_release_hook);\n";
  351. }
  352. out << "\n";
  353. // push return value back on stack and return
  354. if(function->suspend) {
  355. if(!function->return_type.is_void()) {
  356. std::stringstream msg;
  357. msg << "Function '" << function->name << "' declared as suspend"
  358. << " but has a return value.";
  359. throw std::runtime_error(msg.str());
  360. }
  361. out << ind << ind << "return sq_suspendvm(vm);\n";
  362. } else if(function->return_type.is_void()) {
  363. out << ind << ind << "return 0;\n";
  364. } else {
  365. push_to_stack(function->return_type, "return_value");
  366. out << ind << ind << "return 1;\n";
  367. }
  368. out << "\n";
  369. out << ind << "} catch(std::exception& e) {\n";
  370. out << ind << ind << "sq_throwerror(vm, e.what());\n";
  371. out << ind << ind << "return SQ_ERROR;\n";
  372. out << ind << "} catch(...) {\n";
  373. out << ind << ind << "sq_throwerror(vm, _SC(\"Unexpected exception while executing function '" << function->name << "'\"));\n";
  374. out << ind << ind << "return SQ_ERROR;\n";
  375. out << ind << "}\n";
  376. out << "\n";
  377. out << "}\n";
  378. out << "\n";
  379. }
  380. void
  381. WrapperCreator::prepare_argument(const Type& type, size_t index,
  382. const std::string& var)
  383. {
  384. if(type.ref > 0 && type.atomic_type != StringType::instance())
  385. throw std::runtime_error("References not handled yet");
  386. if(type.pointer > 0)
  387. throw std::runtime_error("Pointers not handled yet");
  388. if(type.atomic_type == &BasicType::INT) {
  389. out << ind << "SQInteger " << var << ";\n";
  390. out << ind << "if(SQ_FAILED(sq_getinteger(vm, " << index << ", &" << var << "))) {\n";
  391. out << ind << ind << "sq_throwerror(vm, _SC(\"Argument " << (index-1) << " not an integer\"));\n";
  392. out << ind << ind << "return SQ_ERROR;\n";
  393. out << ind << "}\n";
  394. } else if(type.atomic_type == &BasicType::FLOAT) {
  395. out << ind << "SQFloat " << var << ";\n";
  396. out << ind << "if(SQ_FAILED(sq_getfloat(vm, " << index << ", &" << var << "))) {\n";
  397. out << ind << ind << "sq_throwerror(vm, _SC(\"Argument " << (index-1) << " not a float\"));\n";
  398. out << ind << ind << "return SQ_ERROR;\n";
  399. out << ind << "}\n";
  400. } else if(type.atomic_type == &BasicType::BOOL) {
  401. out << ind << "SQBool " << var << ";\n";
  402. out << ind << "if(SQ_FAILED(sq_getbool(vm, " << index << ", &" << var << "))) {\n";
  403. out << ind << ind << "sq_throwerror(vm, _SC(\"Argument " << (index-1) << " not a bool\"));\n";
  404. out << ind << ind << "return SQ_ERROR;\n";
  405. out << ind << "}\n";
  406. } else if(type.atomic_type == StringType::instance()) {
  407. out << ind << "const SQChar* " << var << ";\n";
  408. out << ind << "if(SQ_FAILED(sq_getstring(vm, " << index << ", &" << var << "))) {\n";
  409. out << ind << ind << "sq_throwerror(vm, _SC(\"Argument " << (index-1) << " not a string\"));\n";
  410. out << ind << ind << "return SQ_ERROR;\n";
  411. out << ind << "}\n";
  412. } else {
  413. std::ostringstream msg;
  414. msg << "Type '" << type.atomic_type->name << "' not supported yet.";
  415. throw std::runtime_error(msg.str());
  416. }
  417. }
  418. void
  419. WrapperCreator::push_to_stack(const Type& type, const std::string& var)
  420. {
  421. if(type.ref > 0 && type.atomic_type != StringType::instance())
  422. throw std::runtime_error("References not handled yet");
  423. if(type.pointer > 0)
  424. throw std::runtime_error("Pointers not handled yet");
  425. out << ind << ind;
  426. if(type.atomic_type == &BasicType::INT) {
  427. out << "sq_pushinteger(vm, " << var << ");\n";
  428. } else if(type.atomic_type == &BasicType::FLOAT) {
  429. out << "sq_pushfloat(vm, " << var << ");\n";
  430. } else if(type.atomic_type == &BasicType::BOOL) {
  431. out << "sq_pushbool(vm, " << var << ");\n";
  432. } else if(type.atomic_type == StringType::instance()) {
  433. out << "assert(" << var << ".size() < static_cast<size_t>(std::numeric_limits<SQInteger>::max()));\n"
  434. << ind << ind << "sq_pushstring(vm, " << var << ".c_str(), static_cast<SQInteger>("
  435. << var << ".size()));\n";
  436. } else {
  437. std::ostringstream msg;
  438. msg << "Type '" << type.atomic_type->name << "' not supported yet.";
  439. throw std::runtime_error(msg.str());
  440. }
  441. }
  442. void
  443. WrapperCreator::create_class_wrapper(Class* _class)
  444. {
  445. create_class_release_hook(_class);
  446. for(auto& member : _class->members) {
  447. if(member->visibility != ClassMember::PUBLIC)
  448. continue;
  449. Function* function = dynamic_cast<Function*> (member);
  450. if(!function)
  451. continue;
  452. // don't wrap destructors
  453. if(function->type == Function::DESTRUCTOR)
  454. continue;
  455. create_function_wrapper(_class, function);
  456. }
  457. }
  458. void
  459. WrapperCreator::create_squirrel_instance(Class* _class)
  460. {
  461. out << "void create_squirrel_instance(HSQUIRRELVM v, "
  462. << ns_prefix << _class->name
  463. << "* object, bool setup_releasehook)\n"
  464. << "{\n"
  465. << ind << "using namespace wrapper;\n"
  466. << "\n"
  467. << ind << "sq_pushroottable(v);\n"
  468. << ind << "sq_pushstring(v, \"" << _class->name << "\", -1);\n"
  469. << ind << "if(SQ_FAILED(sq_get(v, -2))) {\n"
  470. << ind << ind << "std::ostringstream msg;\n"
  471. << ind << ind << "msg << \"Couldn't resolved squirrel type '"
  472. << _class->name << "'\";\n"
  473. << ind << ind << "throw SquirrelError(v, msg.str());\n"
  474. << ind << "}\n"
  475. << "\n"
  476. << ind << "if(SQ_FAILED(sq_createinstance(v, -1)) || "
  477. << "SQ_FAILED(sq_setinstanceup(v, -1, object))) {\n"
  478. << ind << ind << "std::ostringstream msg;\n"
  479. << ind << ind << "msg << \"Couldn't setup squirrel instance for "
  480. << "object of type '" << _class->name << "'\";\n"
  481. << ind << ind << "throw SquirrelError(v, msg.str());\n"
  482. << ind << "}\n"
  483. << ind << "sq_remove(v, -2); // remove object name\n"
  484. << "\n"
  485. << ind << "if(setup_releasehook) {\n"
  486. << ind << ind << "sq_setreleasehook(v, -1, "
  487. << _class->name << "_release_hook);\n"
  488. << ind << "}\n"
  489. << "\n"
  490. << ind << "sq_remove(v, -2); // remove root table\n"
  491. << "}\n"
  492. << "\n";
  493. }
  494. void
  495. WrapperCreator::create_class_release_hook(Class* _class)
  496. {
  497. out << "static SQInteger " << _class->name << "_release_hook(SQUserPointer ptr, SQInteger )\n"
  498. << "{\n"
  499. << ind << "auto _this = reinterpret_cast<" << ns_prefix << _class->name
  500. << "*> (ptr);\n"
  501. << ind << "delete _this;\n"
  502. << ind << "return 0;\n"
  503. << "}\n"
  504. << "\n";
  505. }