create_wrapper.cpp 18 KB

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