fix miniswig using wrong stack numbers in functions with HSQUIRRELVM arguments
[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         << "\n"
28         << "#endif\n"
29         << "\n";
30     
31     // cpp header
32     out << "/**\n"
33         << " * WARNING: This file is automatically generated from:\n"
34         << " *  '" << fromfile << "'\n"
35         << " * DO NOT CHANGE\n"
36         << " */\n"
37         << "#include <config.h>\n"
38         << "\n"
39         << "#include <new>\n"
40         << "#include <assert.h>\n"
41         << "#include <string>\n"
42         << "#include <squirrel.h>\n"
43         << "#include \"wrapper_util.hpp\"\n"
44         << "#include \"wrapper.interface.hpp\"\n"
45         << "\n";
46     if(selected_namespace != "") {
47         out << "using namespace " << selected_namespace << ";\n";
48         out << "\n";
49     }
50     
51     for(std::vector<AtomicType*>::iterator i = ns->types.begin();
52             i != ns->types.end(); ++i) {
53         AtomicType* type = *i;
54         Class* _class = dynamic_cast<Class*> (type);
55         if(_class != 0)
56             create_class_wrapper(_class);
57     }
58     for(std::vector<Function*>::iterator i = ns->functions.begin();
59             i != ns->functions.end(); ++i) {
60         create_function_wrapper(0, *i);
61     }
62
63     // create function list...
64     out << "WrappedFunction " << modulename << "_global_functions[] = {\n";
65     for(std::vector<Function*>::iterator i = ns->functions.begin();
66             i != ns->functions.end(); ++i) {
67         Function* function = *i;
68         out << ind << "{ \"" << function->name << "\", &"
69             << function->name << "_wrapper },\n";
70     }
71     out << ind << "{ 0, 0 }\n"
72         << "};\n"
73         << "\n";
74
75     // create class list...
76     std::ostringstream classlist;
77     classlist << "WrappedClass " << modulename << "_classes[] = {\n";
78
79     for(std::vector<AtomicType*>::iterator i = ns->types.begin();
80             i != ns->types.end(); ++i) {
81         AtomicType* type = *i;
82         Class* _class = dynamic_cast<Class*> (type);
83         if(_class == 0)
84             continue;
85         
86         classlist << ind << "{ \"" << _class->name << "\", "
87             << modulename << "_" << _class->name
88             << "_methods },\n";
89             
90         out << "static WrappedFunction " << modulename << "_"
91             << _class->name << "_methods[] = {\n";
92         for(std::vector<ClassMember*>::iterator i = _class->members.begin();
93                 i != _class->members.end(); ++i) {
94             ClassMember* member = *i;
95             if(member->visibility != ClassMember::PUBLIC)
96                 continue;
97             Function* function = dynamic_cast<Function*> (member);
98             if(!function || function->type == Function::DESTRUCTOR)
99                 continue;
100
101             out << ind << "{ \"" << function->name << "\", &"
102                 << _class->name << "_" << function->name << "_wrapper },\n";
103         }
104         out << "};\n"
105             << "\n";
106     }
107     classlist << ind << "{ 0, 0 }\n";
108     classlist << "};\n";
109     out << classlist.str();
110     out << "\n";
111 }
112
113 void
114 WrapperCreator::create_function_wrapper(Class* _class, Function* function)
115 {
116     if(function->type == Function::DESTRUCTOR)
117         assert(false);
118
119     std::string ns_prefix;
120     if(selected_namespace != "")
121         ns_prefix = selected_namespace + "::";
122     if(function->type == Function::CONSTRUCTOR)
123         function->name = "constructor";
124
125     out << "static int ";
126     if(_class != 0) {
127         out << _class->name << "_";
128     }
129     out << function->name << "_wrapper(HSQUIRRELVM v)\n"
130         << "{\n";
131     // avoid warning...
132     if(_class == 0 && function->parameters.empty() 
133             && function->return_type.is_void()
134             && function->type != Function::CONSTRUCTOR) {
135         out << ind << "(void) v;\n";
136     }
137     
138     // eventually retrieve pointer to class instance
139     if(_class != 0 && function->type != Function::CONSTRUCTOR) {
140         out << ind << ns_prefix <<  _class->name << "* _this;\n";
141         out << ind << "sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0);\n";
142     }
143     
144     // declare and retrieve arguments
145     int i = 0;
146     int arg_offset = 2;
147     for(std::vector<Parameter>::iterator p = function->parameters.begin();
148             p != function->parameters.end(); ++p) {
149         if(i == 0 && p->type.atomic_type == HSQUIRRELVMType::instance()) {
150             out << ind << "HSQUIRRELVM arg0 = v;\n";
151             arg_offset--;
152         } else {
153             char argname[64];
154             snprintf(argname, sizeof(argname), "arg%d", i);
155             prepare_argument(p->type, i + arg_offset, argname);
156         }
157         ++i;
158     }
159     
160     // call function
161     out << ind << "\n";
162     out << ind;
163     if(!function->return_type.is_void()) {
164         function->return_type.write_c_type(out);
165         out << " return_value = ";
166     }
167     if(_class != 0) {
168         if(function->type == Function::CONSTRUCTOR) {
169             out << ns_prefix << _class->name << "* _this = new " << ns_prefix;
170         } else {
171             out << "_this->";
172         }
173     } else {
174         out << ns_prefix;
175     }
176     if(function->type == Function::CONSTRUCTOR) {
177         out << _class->name << "(";
178     } else {
179         out << function->name << "(";
180     }
181     for(size_t i = 0; i < function->parameters.size(); ++i) {
182         if(i != 0)
183             out << ", ";
184         out << "arg" << i;
185     }
186     out << ");\n";
187     if(function->type == Function::CONSTRUCTOR) {
188         out << ind << "sq_setinstanceup(v, 1, _this);\n";
189         out << ind << "sq_setreleasehook(v, 1, " 
190             << _class->name << "_release_hook);\n";
191     }
192     out << ind << "\n";
193     // push return value back on stack and return
194     if(function->return_type.is_void()) {
195         out << ind << "return 0;\n";
196     } else {
197         push_to_stack(function->return_type, "return_value");
198         out << ind << "return 1;\n";
199     }
200     out << "}\n";
201     out << "\n";
202 }
203
204 void
205 WrapperCreator::prepare_argument(const Type& type, size_t index,
206         const std::string& var)
207 {
208     if(type.ref > 0 && type.atomic_type != StringType::instance())
209         throw std::runtime_error("References not handled yet");
210     if(type.pointer > 0)
211         throw std::runtime_error("Pointers not handled yet");
212     if(type.atomic_type == &BasicType::INT) {
213         out << ind << "int " << var << ";\n";
214         out << ind << "sq_getinteger(v, " << index << ", &" << var << ");\n";
215     } else if(type.atomic_type == &BasicType::FLOAT) {
216         out << ind << "float " << var << ";\n";
217         out << ind << "sq_getfloat(v, " << index << ", &" << var << ");\n";
218     } else if(type.atomic_type == &BasicType::BOOL) {
219         out << ind << "SQBool " << var << ";\n";
220         out << ind << "sq_getbool(v, " << index << ", &" << var << ");\n";
221     } else if(type.atomic_type == StringType::instance()) {
222         out << ind << "const char* " << var << ";\n";
223         out << ind << "sq_getstring(v, " << index << ", &" << var << ");\n";
224     } else {
225         std::ostringstream msg;
226         msg << "Type '" << type.atomic_type->name << "' not supported yet.";
227         throw std::runtime_error(msg.str());
228     }
229 }
230
231 void
232 WrapperCreator::push_to_stack(const Type& type, const std::string& var)
233 {
234     if(type.ref > 0 && type.atomic_type != StringType::instance())
235         throw std::runtime_error("References not handled yet");
236     if(type.pointer > 0)
237         throw std::runtime_error("Pointers not handled yet");
238     out << ind;
239     if(type.atomic_type == &BasicType::INT) {
240         out << "sq_pushinteger(v, " << var << ");\n";
241     } else if(type.atomic_type == &BasicType::FLOAT) {
242         out << "sq_pushfloat(v, " << var << ");\n";
243     } else if(type.atomic_type == &BasicType::BOOL) {
244         out << "sq_pushbool(v, " << var << ");\n";
245     } else if(type.atomic_type == StringType::instance()) {
246         out << "sq_pushstring(v, " << var << ".c_str(), " 
247             << var << ".size());\n";
248     } else {
249         std::ostringstream msg;
250         msg << "Type '" << type.atomic_type->name << "' not supported yet.";
251         throw std::runtime_error(msg.str());
252     }
253 }
254
255 void
256 WrapperCreator::create_class_wrapper(Class* _class)
257 {
258     bool release_hook_created = false;
259     for(std::vector<ClassMember*>::iterator i = _class->members.begin();
260             i != _class->members.end(); ++i) {
261         ClassMember* member = *i;
262         if(member->visibility != ClassMember::PUBLIC)
263             continue;
264         Function* function = dynamic_cast<Function*> (member);
265         if(!function)
266             continue;
267         if(function->type == Function::CONSTRUCTOR
268             && !release_hook_created) {
269           create_class_release_hook(_class);
270           release_hook_created = true;
271         }
272         // don't wrap destructors
273         if(function->type == Function::DESTRUCTOR)
274             continue;
275         create_function_wrapper(_class, function);
276     }
277 }
278
279 void
280 WrapperCreator::create_class_release_hook(Class* _class)
281 {
282     out << "static int " << _class->name << "_release_hook(SQUserPointer ptr, int )\n"
283         << "{\n"
284         << ind << _class->name 
285         << "* _this = reinterpret_cast<" << _class->name << "*> (ptr);\n"
286         << ind << "delete _this;\n"
287         << ind << "return 0;\n"
288         << "}\n"
289         << "\n";
290 }
291