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