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