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