4 #include "create_wrapper.hpp"
13 WrapperCreator::create_wrapper(Namespace* ns)
15 std::string fromfile = original_file != "" ? original_file : inputfile;
17 if(selected_namespace != "") {
18 ns_prefix = selected_namespace;
25 << " * WARNING: This file is automatically generated from:\n"
26 << " * '" << fromfile << "'\n"
27 << " * DO NOT CHANGE\n"
29 << "#ifndef HEADER_SUPERTUX_SCRIPTING_WRAPPER_HPP\n" //TODO avoid hardcoding
30 << "#define HEADER_SUPERTUX_SCRIPTING_WRAPPER_HPP\n"
32 << "namespace Scripting {\n"
35 hppout << "void register_" << modulename << "_wrapper(HSQUIRRELVM v);\n"
38 for(std::vector<AtomicType*>::iterator i = ns->types.begin();
39 i != ns->types.end(); ++i) {
40 AtomicType* type = *i;
41 Class* _class = dynamic_cast<Class*> (type);
45 hppout << "class " << _class->name << ";\n";
46 hppout << "void create_squirrel_instance(HSQUIRRELVM v, "
47 << ns_prefix << _class->name
48 << "* object, bool setup_releasehook = false);\n";
59 << " * WARNING: This file is automatically generated from:\n"
60 << " * '" << fromfile << "'\n"
61 << " * DO NOT CHANGE\n"
64 << "#include <sstream>\n"
66 << "#include \"scripting/squirrel_error.hpp\"\n"
67 << "#include \"scripting/wrapper.interface.hpp\"\n"
69 << "namespace Scripting {\n"
70 << "namespace Wrapper {\n"
73 for(std::vector<AtomicType*>::iterator i = ns->types.begin();
74 i != ns->types.end(); ++i) {
75 AtomicType* type = *i;
76 Class* _class = dynamic_cast<Class*> (type);
78 create_class_wrapper(_class);
80 for(std::vector<Function*>::iterator i = ns->functions.begin();
81 i != ns->functions.end(); ++i) {
82 create_function_wrapper(0, *i);
85 out << "} // end of namespace Wrapper\n";
87 for(std::vector<AtomicType*>::iterator i = ns->types.begin();
88 i != ns->types.end(); ++i) {
89 AtomicType* type = *i;
90 Class* _class = dynamic_cast<Class*> (type);
92 create_squirrel_instance(_class);
95 out << "void register_" << modulename << "_wrapper(HSQUIRRELVM v)\n"
97 << ind << "using namespace Wrapper;\n"
100 create_register_constants_code(ns);
101 create_register_functions_code(ns);
102 create_register_classes_code(ns);
106 << "} // end of namespace Scripting\n"
112 WrapperCreator::create_register_function_code(Function* function, Class* _class)
114 if(function->type == Function::DESTRUCTOR)
117 out << ind << "sq_pushstring(v, \"" << function->name << "\", -1);\n";
118 out << ind << "sq_newclosure(v, &"
119 << (_class != 0 ? _class->name + "_" : "") << function->name
120 << "_wrapper, 0);\n";
122 if(function->custom) {
123 out << ind << "sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, " << function->parameter_spec << ");\n";
125 out << ind << "sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, \"";
129 if(!function->parameters.empty())
131 std::vector<Parameter>::iterator p = function->parameters.begin();
133 // Skip the first parameter since its a HSQUIRRELVM that is
134 // handled internally
135 if (function->suspend) {
137 } else if (p->type.atomic_type == HSQUIRRELVMType::instance()) {
141 for(; p != function->parameters.end(); ++p) {
142 if(p->type.atomic_type == &BasicType::INT) {
144 } else if(p->type.atomic_type == &BasicType::FLOAT) {
146 } else if(p->type.atomic_type == &BasicType::BOOL) {
148 } else if(p->type.atomic_type == StringType::instance()) {
158 create_register_slot_code("function", function->name);
163 WrapperCreator::create_register_functions_code(Namespace* ns)
165 for(std::vector<Function*>::iterator i = ns->functions.begin();
166 i != ns->functions.end(); ++i) {
167 Function* function = *i;
168 create_register_function_code(function, 0);
173 WrapperCreator::create_register_classes_code(Namespace* ns)
175 for(std::vector<AtomicType*>::iterator i = ns->types.begin();
176 i != ns->types.end(); ++i) {
177 AtomicType* type = *i;
178 Class* _class = dynamic_cast<Class*> (type);
181 if(_class->super_classes.size() > 0)
184 create_register_class_code(_class);
189 WrapperCreator::create_register_class_code(Class* _class)
191 out << ind << "// Register class " << _class->name << "\n";
192 out << ind << "sq_pushstring(v, \""
193 << _class->name << "\", -1);\n";
195 if(_class->super_classes.size() > 0) {
196 if(_class->super_classes.size() > 1) {
197 std::ostringstream msg;
198 msg << "Multiple inheritance not supported (at class '"
199 << _class->name << "')";
200 throw std::runtime_error(msg.str());
203 out << ind << "sq_pushstring(v, \""
204 << _class->super_classes[0]->name << "\", -1);\n";
205 out << ind << "sq_get(v, -3);\n";
207 out << ind << "if(sq_newclass(v, "
208 << (_class->super_classes.size() > 0 ? "SQTrue" : "SQFalse")
210 out << ind << ind << "std::ostringstream msg;\n";
211 out << ind << ind << "msg << \"Couldn't create new class '"
212 << _class->name << "'\";\n";
213 out << ind << ind << "throw SquirrelError(v, msg.str());\n";
216 for(std::vector<ClassMember*>::iterator i = _class->members.begin();
217 i != _class->members.end(); ++i) {
218 ClassMember* member = *i;
219 if(member->visibility != ClassMember::PUBLIC)
221 Function* function = dynamic_cast<Function*> (member);
223 create_register_function_code(function, _class);
225 Field* field = dynamic_cast<Field*> (member);
227 create_register_constant_code(field);
231 create_register_slot_code("class", _class->name);
234 for(std::vector<Class*>::iterator i = _class->sub_classes.begin();
235 i != _class->sub_classes.end(); ++i) {
237 create_register_class_code(_class);
242 WrapperCreator::create_register_constants_code(Namespace* ns)
244 for(std::vector<Field*>::iterator i = ns->fields.begin();
245 i != ns->fields.end(); ++i) {
247 create_register_constant_code(field);
252 WrapperCreator::create_register_constant_code(Field* field)
254 if(!field->has_const_value)
256 out << ind << "sq_pushstring(v, \"" << field->name << "\", -1);\n";
257 if(field->type->atomic_type == &BasicType::INT) {
258 out << ind << "sq_pushinteger(v, " << field->const_int_value << ");\n";
259 } else if(field->type->atomic_type == &BasicType::FLOAT) {
260 out << ind << "sq_pushfloat(v, " << field->const_float_value << ");\n";
261 } else if(field->type->atomic_type == StringType::instance()) {
262 out << ind << "sq_pushstring(v, \""
263 << field->const_string_value << "\", -1);\n";
265 throw std::runtime_error("Constant is not int, float or string");
267 create_register_slot_code("constant", field->name);
272 WrapperCreator::create_register_slot_code(const std::string& what,
273 const std::string& name)
275 out << ind << "if(SQ_FAILED(sq_createslot(v, -3))) {\n";
276 out << ind << ind << "throw SquirrelError(v, \""
277 << "Couldn't register " << what << " '" << name << "'\");\n";
282 WrapperCreator::create_function_wrapper(Class* _class, Function* function)
284 if(function->type == Function::DESTRUCTOR)
287 std::string ns_prefix;
288 if(selected_namespace != "")
289 ns_prefix = selected_namespace + "::";
290 if(function->type == Function::CONSTRUCTOR)
291 function->name = "constructor";
293 out << "static SQInteger ";
295 out << _class->name << "_";
297 out << function->name << "_wrapper(HSQUIRRELVM vm)\n"
300 if(_class == 0 && function->parameters.empty()
301 && function->return_type.is_void()
302 && function->type != Function::CONSTRUCTOR) {
303 out << ind << "(void) vm;\n";
306 // retrieve pointer to class instance
307 if(_class != 0 && function->type != Function::CONSTRUCTOR) {
308 out << ind << "SQUserPointer data;\n";
309 out << ind << "if(SQ_FAILED(sq_getinstanceup(vm, 1, &data, 0)) || !data) {\n";
310 out << ind << ind << "sq_throwerror(vm, _SC(\"'" << function->name << "' called without instance\"));\n";
311 out << ind << ind << "return SQ_ERROR;\n";
313 out << ind << ns_prefix << _class->name << "* _this = reinterpret_cast<" << ns_prefix << _class->name << "*> (data);\n";
317 if(function->custom) {
318 if(function->type != Function::FUNCTION)
319 throw std::runtime_error(
320 "custom not allow constructor+destructor yet");
321 if(function->return_type.atomic_type != SQIntegerType::instance())
322 throw std::runtime_error("custom function '" + function->name + "' has to return SQInteger");
323 if(function->parameters.size() != 1)
324 throw std::runtime_error(
325 "custom function '" + function->name + "' must have 1 HSQUIRRELVM parameter");
327 out << ind << "return ";
332 out << function->name << "(vm);\n";
338 // declare and retrieve arguments
341 for(std::vector<Parameter>::iterator p = function->parameters.begin();
342 p != function->parameters.end(); ++p) {
343 if(i == 0 && p->type.atomic_type == HSQUIRRELVMType::instance()) {
344 out << ind << "HSQUIRRELVM arg0 = vm;\n";
348 snprintf(argname, sizeof(argname), "arg%d", i);
349 prepare_argument(p->type, i + arg_offset, argname);
356 out << ind << "try {\n";
358 if(!function->return_type.is_void()) {
359 function->return_type.write_c_type(out);
360 out << " return_value = ";
363 if(function->type == Function::CONSTRUCTOR) {
364 out << ns_prefix << _class->name << "* _this = new " << ns_prefix;
371 if(function->type == Function::CONSTRUCTOR) {
372 out << _class->name << "(";
374 out << function->name << "(";
376 for(size_t i = 0; i < function->parameters.size(); ++i) {
379 const Parameter param = function->parameters[i];
380 if(param.type.ref == 0 && param.type.pointer == 0) {
381 if(param.type.atomic_type == &BasicType::INT)
382 out << "static_cast<int> (arg" << i << ")";
383 else if(param.type.atomic_type == &BasicType::FLOAT)
384 out << "static_cast<float> (arg" << i << ")";
385 else if(param.type.atomic_type == &BasicType::BOOL)
386 out << "arg" << i << " == SQTrue";
394 if(function->type == Function::CONSTRUCTOR) {
395 out << ind << "if(SQ_FAILED(sq_setinstanceup(vm, 1, _this))) {\n";
396 out << ind << ind << "sq_throwerror(vm, _SC(\"Couldn't setup instance of '" << _class->name << "' class\"));\n";
397 out << ind << ind << "return SQ_ERROR;\n";
399 out << ind << "sq_setreleasehook(vm, 1, "
400 << _class->name << "_release_hook);\n";
403 // push return value back on stack and return
404 if(function->suspend) {
405 if(!function->return_type.is_void()) {
406 std::stringstream msg;
407 msg << "Function '" << function->name << "' declared as suspend"
408 << " but has a return value.";
409 throw std::runtime_error(msg.str());
411 out << ind << ind << "return sq_suspendvm(vm);\n";
412 } else if(function->return_type.is_void()) {
413 out << ind << ind << "return 0;\n";
415 push_to_stack(function->return_type, "return_value");
416 out << ind << ind << "return 1;\n";
420 out << ind << "} catch(std::exception& e) {\n";
421 out << ind << ind << "sq_throwerror(vm, e.what());\n";
422 out << ind << ind << "return SQ_ERROR;\n";
423 out << ind << "} catch(...) {\n";
424 out << ind << ind << "sq_throwerror(vm, _SC(\"Unexpected exception while executing function '" << function->name << "'\"));\n";
425 out << ind << ind << "return SQ_ERROR;\n";
434 WrapperCreator::prepare_argument(const Type& type, size_t index,
435 const std::string& var)
437 if(type.ref > 0 && type.atomic_type != StringType::instance())
438 throw std::runtime_error("References not handled yet");
440 throw std::runtime_error("Pointers not handled yet");
441 if(type.atomic_type == &BasicType::INT) {
442 out << ind << "SQInteger " << var << ";\n";
443 out << ind << "if(SQ_FAILED(sq_getinteger(vm, " << index << ", &" << var << "))) {\n";
444 out << ind << ind << "sq_throwerror(vm, _SC(\"Argument " << (index-1) << " not an integer\"));\n";
445 out << ind << ind << "return SQ_ERROR;\n";
447 } else if(type.atomic_type == &BasicType::FLOAT) {
448 out << ind << "SQFloat " << var << ";\n";
449 out << ind << "if(SQ_FAILED(sq_getfloat(vm, " << index << ", &" << var << "))) {\n";
450 out << ind << ind << "sq_throwerror(vm, _SC(\"Argument " << (index-1) << " not a float\"));\n";
451 out << ind << ind << "return SQ_ERROR;\n";
453 } else if(type.atomic_type == &BasicType::BOOL) {
454 out << ind << "SQBool " << var << ";\n";
455 out << ind << "if(SQ_FAILED(sq_getbool(vm, " << index << ", &" << var << "))) {\n";
456 out << ind << ind << "sq_throwerror(vm, _SC(\"Argument " << (index-1) << " not a bool\"));\n";
457 out << ind << ind << "return SQ_ERROR;\n";
459 } else if(type.atomic_type == StringType::instance()) {
460 out << ind << "const SQChar* " << var << ";\n";
461 out << ind << "if(SQ_FAILED(sq_getstring(vm, " << index << ", &" << var << "))) {\n";
462 out << ind << ind << "sq_throwerror(vm, _SC(\"Argument " << (index-1) << " not a string\"));\n";
463 out << ind << ind << "return SQ_ERROR;\n";
466 std::ostringstream msg;
467 msg << "Type '" << type.atomic_type->name << "' not supported yet.";
468 throw std::runtime_error(msg.str());
473 WrapperCreator::push_to_stack(const Type& type, const std::string& var)
475 if(type.ref > 0 && type.atomic_type != StringType::instance())
476 throw std::runtime_error("References not handled yet");
478 throw std::runtime_error("Pointers not handled yet");
480 if(type.atomic_type == &BasicType::INT) {
481 out << "sq_pushinteger(vm, " << var << ");\n";
482 } else if(type.atomic_type == &BasicType::FLOAT) {
483 out << "sq_pushfloat(vm, " << var << ");\n";
484 } else if(type.atomic_type == &BasicType::BOOL) {
485 out << "sq_pushbool(vm, " << var << ");\n";
486 } else if(type.atomic_type == StringType::instance()) {
487 out << "sq_pushstring(vm, " << var << ".c_str(), "
488 << var << ".size());\n";
490 std::ostringstream msg;
491 msg << "Type '" << type.atomic_type->name << "' not supported yet.";
492 throw std::runtime_error(msg.str());
497 WrapperCreator::create_class_wrapper(Class* _class)
499 create_class_release_hook(_class);
500 for(std::vector<ClassMember*>::iterator i = _class->members.begin();
501 i != _class->members.end(); ++i) {
502 ClassMember* member = *i;
503 if(member->visibility != ClassMember::PUBLIC)
505 Function* function = dynamic_cast<Function*> (member);
508 // don't wrap destructors
509 if(function->type == Function::DESTRUCTOR)
511 create_function_wrapper(_class, function);
516 WrapperCreator::create_squirrel_instance(Class* _class)
518 out << "void create_squirrel_instance(HSQUIRRELVM v, "
519 << ns_prefix << _class->name
520 << "* object, bool setup_releasehook)\n"
522 << ind << "using namespace Wrapper;\n"
524 << ind << "sq_pushroottable(v);\n"
525 << ind << "sq_pushstring(v, \"" << _class->name << "\", -1);\n"
526 << ind << "if(SQ_FAILED(sq_get(v, -2))) {\n"
527 << ind << ind << "std::ostringstream msg;\n"
528 << ind << ind << "msg << \"Couldn't resolved squirrel type '"
529 << _class->name << "'\";\n"
530 << ind << ind << "throw SquirrelError(v, msg.str());\n"
533 << ind << "if(SQ_FAILED(sq_createinstance(v, -1)) || "
534 << "SQ_FAILED(sq_setinstanceup(v, -1, object))) {\n"
535 << ind << ind << "std::ostringstream msg;\n"
536 << ind << ind << "msg << \"Couldn't setup squirrel instance for "
537 << "object of type '" << _class->name << "'\";\n"
538 << ind << ind << "throw SquirrelError(v, msg.str());\n"
540 << ind << "sq_remove(v, -2); // remove object name\n"
542 << ind << "if(setup_releasehook) {\n"
543 << ind << ind << "sq_setreleasehook(v, -1, "
544 << _class->name << "_release_hook);\n"
547 << ind << "sq_remove(v, -2); // remove root table\n"
553 WrapperCreator::create_class_release_hook(Class* _class)
555 out << "static SQInteger " << _class->name << "_release_hook(SQUserPointer ptr, SQInteger )\n"
557 << ind << ns_prefix << _class->name
558 << "* _this = reinterpret_cast<" << ns_prefix << _class->name
560 << ind << "delete _this;\n"
561 << ind << "return 0;\n"