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