supports suspending functions
[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         if(function->docu_comment.find("@SUSPEND@") != std::string::npos) {
196           out << ind << "sq_suspendvm(v);\n";
197         } else {
198           out << ind << "return 0;\n";
199         }
200     } else {
201         push_to_stack(function->return_type, "return_value");
202         out << ind << "return 1;\n";
203     }
204     out << "}\n";
205     out << "\n";
206 }
207
208 void
209 WrapperCreator::prepare_argument(const Type& type, size_t index,
210         const std::string& var)
211 {
212     if(type.ref > 0 && type.atomic_type != StringType::instance())
213         throw std::runtime_error("References not handled yet");
214     if(type.pointer > 0)
215         throw std::runtime_error("Pointers not handled yet");
216     if(type.atomic_type == &BasicType::INT) {
217         out << ind << "int " << var << ";\n";
218         out << ind << "sq_getinteger(v, " << index << ", &" << var << ");\n";
219     } else if(type.atomic_type == &BasicType::FLOAT) {
220         out << ind << "float " << var << ";\n";
221         out << ind << "sq_getfloat(v, " << index << ", &" << var << ");\n";
222     } else if(type.atomic_type == &BasicType::BOOL) {
223         out << ind << "SQBool " << var << ";\n";
224         out << ind << "sq_getbool(v, " << index << ", &" << var << ");\n";
225     } else if(type.atomic_type == StringType::instance()) {
226         out << ind << "const char* " << var << ";\n";
227         out << ind << "sq_getstring(v, " << index << ", &" << var << ");\n";
228     } else {
229         std::ostringstream msg;
230         msg << "Type '" << type.atomic_type->name << "' not supported yet.";
231         throw std::runtime_error(msg.str());
232     }
233 }
234
235 void
236 WrapperCreator::push_to_stack(const Type& type, const std::string& var)
237 {
238     if(type.ref > 0 && type.atomic_type != StringType::instance())
239         throw std::runtime_error("References not handled yet");
240     if(type.pointer > 0)
241         throw std::runtime_error("Pointers not handled yet");
242     out << ind;
243     if(type.atomic_type == &BasicType::INT) {
244         out << "sq_pushinteger(v, " << var << ");\n";
245     } else if(type.atomic_type == &BasicType::FLOAT) {
246         out << "sq_pushfloat(v, " << var << ");\n";
247     } else if(type.atomic_type == &BasicType::BOOL) {
248         out << "sq_pushbool(v, " << var << ");\n";
249     } else if(type.atomic_type == StringType::instance()) {
250         out << "sq_pushstring(v, " << var << ".c_str(), " 
251             << var << ".size());\n";
252     } else {
253         std::ostringstream msg;
254         msg << "Type '" << type.atomic_type->name << "' not supported yet.";
255         throw std::runtime_error(msg.str());
256     }
257 }
258
259 void
260 WrapperCreator::create_class_wrapper(Class* _class)
261 {
262     bool release_hook_created = false;
263     for(std::vector<ClassMember*>::iterator i = _class->members.begin();
264             i != _class->members.end(); ++i) {
265         ClassMember* member = *i;
266         if(member->visibility != ClassMember::PUBLIC)
267             continue;
268         Function* function = dynamic_cast<Function*> (member);
269         if(!function)
270             continue;
271         if(function->type == Function::CONSTRUCTOR
272             && !release_hook_created) {
273           create_class_release_hook(_class);
274           release_hook_created = true;
275         }
276         // don't wrap destructors
277         if(function->type == Function::DESTRUCTOR)
278             continue;
279         create_function_wrapper(_class, function);
280     }
281 }
282
283 void
284 WrapperCreator::create_class_release_hook(Class* _class)
285 {
286     out << "static int " << _class->name << "_release_hook(SQUserPointer ptr, int )\n"
287         << "{\n"
288         << ind << _class->name 
289         << "* _this = reinterpret_cast<" << _class->name << "*> (ptr);\n"
290         << ind << "delete _this;\n"
291         << ind << "return 0;\n"
292         << "}\n"
293         << "\n";
294 }
295