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