more squirrel warning fixes
[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         out << ind << "{ \"constructor\", &"
89             << _class->name << "_" << "construct_wrapper },\n";
90         for(std::vector<ClassMember*>::iterator i = _class->members.begin();
91                 i != _class->members.end(); ++i) {
92             ClassMember* member = *i;
93             if(member->visibility != ClassMember::PUBLIC)
94                 continue;
95             Function* function = dynamic_cast<Function*> (member);
96             if(!function || function->type != Function::FUNCTION)
97                 continue;
98
99             out << ind << "{ \"" << function->name << "\", &"
100                 << _class->name << "_" << function->name << "_wrapper },\n";
101         }
102         out << "};\n"
103             << "\n";
104     }
105     classlist << ind << "{ 0, 0 }\n";
106     classlist << "};\n";
107     out << classlist.str();
108     out << "\n";
109 }
110
111 void
112 WrapperCreator::create_function_wrapper(Class* _class, Function* function)
113 {
114     if(function->type == Function::CONSTRUCTOR)
115         throw std::runtime_error("Constructors not supported yet");
116     if(function->type == Function::DESTRUCTOR)
117         throw std::runtime_error("Destructors not supported yet");
118     
119     out << "static int ";
120     if(_class != 0) {
121         out << _class->name << "_";
122     }
123     out << function->name << "_wrapper(HSQUIRRELVM v)\n"
124         << "{\n";
125     // avoid warning...
126     if(_class == 0 && function->parameters.empty() 
127             && function->return_type.is_void()) {
128         out << ind << "(void) v;\n";
129     }
130     
131     // eventually retrieve pointer to class
132     if(_class != 0) {
133         out << ind << _class->name << "* _this;\n";
134         out << ind << "sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0);\n";
135         out << ind << "assert(_this != 0);\n";
136     }
137     
138     // declare and retrieve arguments
139     size_t i = 0;
140     for(std::vector<Parameter>::iterator p = function->parameters.begin();
141             p != function->parameters.end(); ++p) {
142         char argname[64];
143         snprintf(argname, sizeof(argname), "arg%u", i);
144         prepare_argument(p->type, i + 2, argname);
145  
146         ++i;
147     }
148     // call function
149     out << ind << "\n";
150     out << ind;
151     if(!function->return_type.is_void()) {
152         function->return_type.write_c_type(out);
153         out << " return_value = ";
154     }
155     if(_class != 0) {
156         out << "_this->";
157     } else if(selected_namespace != "") {
158         out << selected_namespace << "::";
159     }
160     out << function->name << "(";
161     for(size_t i = 0; i < function->parameters.size(); ++i) {
162         if(i != 0)
163             out << ", ";
164         out << "arg" << i;
165     }
166     out << ");\n";
167     out << ind << "\n";
168     // push return value back on stack and return
169     if(function->return_type.is_void()) {
170         out << ind << "return 0;\n";
171     } else {
172         push_to_stack(function->return_type, "return_value");
173         out << ind << "return 1;\n";
174     }
175     out << "}\n";
176     out << "\n";
177 }
178
179 void
180 WrapperCreator::prepare_argument(const Type& type, size_t index,
181         const std::string& var)
182 {
183     if(type.ref > 0 && type.atomic_type != StringType::instance())
184         throw std::runtime_error("References not handled yet");
185     if(type.pointer > 0)
186         throw std::runtime_error("Pointers not handled yet");
187     if(type.atomic_type == &BasicType::INT) {
188         out << ind << "int " << var << ";\n";
189         out << ind << "sq_getinteger(v, " << index << ", &" << var << ");\n";
190     } else if(type.atomic_type == &BasicType::FLOAT) {
191         out << ind << "float " << var << ";\n";
192         out << ind << "sq_getfloat(v, " << index << ", &" << var << ");\n";
193     } else if(type.atomic_type == &BasicType::BOOL) {
194         out << ind << "SQBool " << var << ";\n";
195         out << ind << "sq_getbool(v, " << index << ", &" << var << ");\n";
196     } else if(type.atomic_type == StringType::instance()) {
197         out << ind << "const char* " << var << ";\n";
198         out << ind << "sq_getstring(v, " << index << ", &" << var << ");\n";
199     } else {
200         std::ostringstream msg;
201         msg << "Type '" << type.atomic_type->name << "' not supported yet.";
202         throw std::runtime_error(msg.str());
203     }
204 }
205
206 void
207 WrapperCreator::push_to_stack(const Type& type, const std::string& var)
208 {
209     if(type.ref > 0 && type.atomic_type != StringType::instance())
210         throw std::runtime_error("References not handled yet");
211     if(type.pointer > 0)
212         throw std::runtime_error("Pointers not handled yet");
213     out << ind;
214     if(type.atomic_type == &BasicType::INT) {
215         out << "sq_pushinteger(v, " << var << ");\n";
216     } else if(type.atomic_type == &BasicType::FLOAT) {
217         out << "sq_pushfloat(v, " << var << ");\n";
218     } else if(type.atomic_type == &BasicType::BOOL) {
219         out << "sq_pushbool(v, " << var << ");\n";
220     } else if(type.atomic_type == StringType::instance()) {
221         out << "sq_pushstring(v, " << var << ".c_str(), " 
222             << var << ".size());\n";
223     } else {
224         std::ostringstream msg;
225         msg << "Type '" << type.atomic_type->name << "' not supported yet.";
226         throw std::runtime_error(msg.str());
227     }
228 }
229
230 void
231 WrapperCreator::create_class_wrapper(Class* _class)
232 {
233     create_class_destruct_function(_class);
234     create_class_construct_function(_class);
235     for(std::vector<ClassMember*>::iterator i = _class->members.begin();
236             i != _class->members.end(); ++i) {
237         ClassMember* member = *i;
238         if(member->visibility != ClassMember::PUBLIC)
239             continue;
240         Function* function = dynamic_cast<Function*> (member);
241         if(!function)
242             continue;
243         // don't wrap constructors and destructors (for now...)
244         if(function->type != Function::FUNCTION)
245             continue;
246         create_function_wrapper(_class, function);
247     }
248 }
249
250 void
251 WrapperCreator::create_class_construct_function(Class* _class)
252 {
253     out << "static int " << _class->name << "_construct_wrapper(HSQUIRRELVM v)\n";
254     out << "{\n";
255     out << ind << _class->name << "* _this = new "
256         << _class->name << "();\n";
257     out << ind << "sq_setinstanceup(v, 1, _this);\n";
258     out << ind << "sq_setreleasehook(v, 1, " 
259         << _class->name << "_release_wrapper);\n";
260     out << "\n";
261     out << ind << "return 0;\n";
262     out << "}\n";
263     out << "\n";
264 }
265
266 void
267 WrapperCreator::create_class_destruct_function(Class* _class)
268 {
269     out << "static int " << _class->name << "_release_wrapper(SQUserPointer ptr, int )\n"
270         << "{\n"
271         << ind << _class->name 
272         << "* _this = reinterpret_cast<" << _class->name << "*> (ptr);\n"
273         << ind << "delete _this;\n"
274         << ind << "return 0;\n"
275         << "}\n"
276         << "\n";
277 }
278