83c6d2aab570b276fcc15d6c045cb1a2b8a62ede
[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     for(std::vector<Parameter>::iterator p = function->parameters.begin();
143             p != function->parameters.end(); ++p) {
144         char argname[64];
145         snprintf(argname, sizeof(argname), "arg%d", i);
146         prepare_argument(p->type, i + 2, argname);
147  
148         ++i;
149     }
150     
151     // call function
152     out << ind << "\n";
153     out << ind;
154     if(!function->return_type.is_void()) {
155         function->return_type.write_c_type(out);
156         out << " return_value = ";
157     }
158     if(_class != 0) {
159         if(function->type == Function::CONSTRUCTOR) {
160             out << ns_prefix << _class->name << "* _this = new " << ns_prefix;
161         } else {
162             out << "_this->";
163         }
164     } else {
165         out << ns_prefix;
166     }
167     if(function->type == Function::CONSTRUCTOR) {
168         out << _class->name << "(";
169     } else {
170         out << function->name << "(";
171     }
172     for(size_t i = 0; i < function->parameters.size(); ++i) {
173         if(i != 0)
174             out << ", ";
175         out << "arg" << i;
176     }
177     out << ");\n";
178     if(function->type == Function::CONSTRUCTOR) {
179         out << ind << "sq_setinstanceup(v, 1, _this);\n";
180         out << ind << "sq_setreleasehook(v, 1, " 
181             << _class->name << "_release_hook);\n";
182     }
183     out << ind << "\n";
184     // push return value back on stack and return
185     if(function->return_type.is_void()) {
186         out << ind << "return 0;\n";
187     } else {
188         push_to_stack(function->return_type, "return_value");
189         out << ind << "return 1;\n";
190     }
191     out << "}\n";
192     out << "\n";
193 }
194
195 void
196 WrapperCreator::prepare_argument(const Type& type, size_t index,
197         const std::string& var)
198 {
199     if(type.ref > 0 && type.atomic_type != StringType::instance())
200         throw std::runtime_error("References not handled yet");
201     if(type.pointer > 0)
202         throw std::runtime_error("Pointers not handled yet");
203     if(type.atomic_type == &BasicType::INT) {
204         out << ind << "int " << var << ";\n";
205         out << ind << "sq_getinteger(v, " << index << ", &" << var << ");\n";
206     } else if(type.atomic_type == &BasicType::FLOAT) {
207         out << ind << "float " << var << ";\n";
208         out << ind << "sq_getfloat(v, " << index << ", &" << var << ");\n";
209     } else if(type.atomic_type == &BasicType::BOOL) {
210         out << ind << "SQBool " << var << ";\n";
211         out << ind << "sq_getbool(v, " << index << ", &" << var << ");\n";
212     } else if(type.atomic_type == StringType::instance()) {
213         out << ind << "const char* " << var << ";\n";
214         out << ind << "sq_getstring(v, " << index << ", &" << var << ");\n";
215     } else {
216         std::ostringstream msg;
217         msg << "Type '" << type.atomic_type->name << "' not supported yet.";
218         throw std::runtime_error(msg.str());
219     }
220 }
221
222 void
223 WrapperCreator::push_to_stack(const Type& type, const std::string& var)
224 {
225     if(type.ref > 0 && type.atomic_type != StringType::instance())
226         throw std::runtime_error("References not handled yet");
227     if(type.pointer > 0)
228         throw std::runtime_error("Pointers not handled yet");
229     out << ind;
230     if(type.atomic_type == &BasicType::INT) {
231         out << "sq_pushinteger(v, " << var << ");\n";
232     } else if(type.atomic_type == &BasicType::FLOAT) {
233         out << "sq_pushfloat(v, " << var << ");\n";
234     } else if(type.atomic_type == &BasicType::BOOL) {
235         out << "sq_pushbool(v, " << var << ");\n";
236     } else if(type.atomic_type == StringType::instance()) {
237         out << "sq_pushstring(v, " << var << ".c_str(), " 
238             << var << ".size());\n";
239     } else {
240         std::ostringstream msg;
241         msg << "Type '" << type.atomic_type->name << "' not supported yet.";
242         throw std::runtime_error(msg.str());
243     }
244 }
245
246 void
247 WrapperCreator::create_class_wrapper(Class* _class)
248 {
249     bool release_hook_created = false;
250     for(std::vector<ClassMember*>::iterator i = _class->members.begin();
251             i != _class->members.end(); ++i) {
252         ClassMember* member = *i;
253         if(member->visibility != ClassMember::PUBLIC)
254             continue;
255         Function* function = dynamic_cast<Function*> (member);
256         if(!function)
257             continue;
258         if(function->type == Function::CONSTRUCTOR
259             && !release_hook_created) {
260           create_class_release_hook(_class);
261           release_hook_created = true;
262         }
263         // don't wrap destructors
264         if(function->type == Function::DESTRUCTOR)
265             continue;
266         create_function_wrapper(_class, function);
267     }
268 }
269
270 void
271 WrapperCreator::create_class_release_hook(Class* _class)
272 {
273     out << "static int " << _class->name << "_release_hook(SQUserPointer ptr, int )\n"
274         << "{\n"
275         << ind << _class->name 
276         << "* _this = reinterpret_cast<" << _class->name << "*> (ptr);\n"
277         << ind << "delete _this;\n"
278         << ind << "return 0;\n"
279         << "}\n"
280         << "\n";
281 }
282