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