5ab41fe05882063d1b5f0a979bbbbe031cfb6e9b
[cparser] / wrappergen / write_jna.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include <config.h>
21
22 #include <errno.h>
23 #include <string.h>
24
25 #include "write_jna.h"
26 #include "symbol_t.h"
27 #include "ast_t.h"
28 #include "type_t.h"
29 #include "entity_t.h"
30 #include "type.h"
31 #include "printer.h"
32 #include "adt/error.h"
33 #include <libfirm/adt/pset_new.h>
34
35 static const scope_t *global_scope;
36 static FILE          *out;
37 static pset_new_t     avoid_symbols;
38
39 static void write_type(type_t *type);
40
41 static bool is_system_header(const char *fname)
42 {
43         return strncmp(fname, "/usr/include", 12) == 0;
44 }
45
46 static const char *fix_builtin_names(const char *name)
47 {
48         if (strcmp(name, "class") == 0) {
49                 return "_class";
50         } else if(strcmp(name, "this") == 0) {
51                 return "_this";
52         } else if(strcmp(name, "public") == 0) {
53                 return "_public";
54         } else if(strcmp(name, "protected") == 0) {
55                 return "_protected";
56         } else if(strcmp(name, "private") == 0) {
57                 return "_private";
58         } else if(strcmp(name, "final") == 0) {
59                 return "_final";
60         }
61         /* TODO put all reserved names here */
62         return name;
63 }
64
65 static const char *get_atomic_type_string(const atomic_type_kind_t type)
66 {
67         switch(type) {
68         case ATOMIC_TYPE_VOID:        return "void";
69         case ATOMIC_TYPE_CHAR:        return "byte";
70         case ATOMIC_TYPE_SCHAR:       return "byte";
71         case ATOMIC_TYPE_UCHAR:       return "byte";
72         case ATOMIC_TYPE_SHORT:       return "short";
73         case ATOMIC_TYPE_USHORT:      return "short";
74         case ATOMIC_TYPE_INT:         return "int";
75         case ATOMIC_TYPE_UINT:        return "int";
76         case ATOMIC_TYPE_LONG:        return "com.sun.jna.NativeLong";
77         case ATOMIC_TYPE_ULONG:       return "com.sun.jna.NativeLong";
78         case ATOMIC_TYPE_LONGLONG:    return "long";
79         case ATOMIC_TYPE_ULONGLONG:   return "long";
80         case ATOMIC_TYPE_FLOAT:       return "float";
81         case ATOMIC_TYPE_DOUBLE:      return "double";
82         case ATOMIC_TYPE_LONG_DOUBLE: return "double";
83         case ATOMIC_TYPE_BOOL:        return "boolean";
84         default:                      panic("unsupported atomic type");
85         }
86 }
87
88 static void write_atomic_type(const atomic_type_t *type)
89 {
90         fputs(get_atomic_type_string(type->akind), out);
91 }
92
93 static void write_pointer_type(const pointer_type_t *type)
94 {
95         type_t *points_to = skip_typeref(type->points_to);
96         if (is_type_atomic(points_to, ATOMIC_TYPE_CHAR)) {
97                 fputs("String", out);
98                 return;
99         }
100         if (is_type_pointer(points_to)) {
101                 /* hack... */
102                 fputs("Pointer[]", out);
103                 return;
104         }
105         fputs("Pointer", out);
106 }
107
108 static entity_t *find_typedef(const type_t *type)
109 {
110         /* first: search for a matching typedef in the global type... */
111         entity_t *entity = global_scope->entities;
112         for ( ; entity != NULL; entity = entity->base.next) {
113                 if (entity->kind != ENTITY_TYPEDEF)
114                         continue;
115                 if (entity->typedefe.type == type)
116                         break;
117         }
118
119         return entity;
120 }
121
122 static entity_t *find_enum_typedef(const enum_t *enume)
123 {
124         /* first: search for a matching typedef in the global type... */
125         entity_t *entity = global_scope->entities;
126         for ( ; entity != NULL; entity = entity->base.next) {
127                 if (entity->kind != ENTITY_TYPEDEF)
128                         continue;
129                 type_t *type = entity->typedefe.type;
130                 if (type->kind != TYPE_ENUM)
131                         continue;
132
133                 enum_t *e_entity = type->enumt.enume;
134                 if (e_entity == enume)
135                         break;
136         }
137
138         return entity;
139 }
140
141 static void write_compound_type(const compound_type_t *type)
142 {
143         entity_t *entity = find_typedef((const type_t*) type);
144         if(entity != NULL) {
145                 fputs(entity->base.symbol->string, out);
146                 return;
147         }
148
149         /* does the struct have a name? */
150         symbol_t *symbol = type->compound->base.symbol;
151         if(symbol != NULL) {
152                 /* TODO: make sure we create a struct for it... */
153                 fputs(symbol->string, out);
154                 return;
155         }
156         /* TODO: create a struct and use its name here... */
157         fputs("/* TODO anonymous struct */byte", out);
158 }
159
160 static void write_enum_name(const enum_type_t *type)
161 {
162         entity_t *entity = find_typedef((const type_t*) type);
163         if (entity != NULL) {
164                 fputs(entity->base.symbol->string, out);
165                 return;
166         }
167
168         /* does the enum have a name? */
169         symbol_t *symbol = type->enume->base.symbol;
170         if (symbol != NULL) {
171                 /* TODO: make sure we create an enum for it... */
172                 fputs(symbol->string, out);
173                 return;
174         }
175
176         /* now we have a problem as we don't know how we'll call the anonymous
177          * enum */
178         panic("can't reference entries from anonymous enums yet");
179 }
180
181 static void write_enum_type(const enum_type_t *type)
182 {
183         entity_t *entity = find_typedef((const type_t*) type);
184         if (entity != NULL) {
185                 fprintf(out, "/* %s */int", entity->base.symbol->string);
186                 return;
187         }
188
189         /* does the enum have a name? */
190         symbol_t *symbol = type->enume->base.symbol;
191         if (symbol != NULL) {
192                 /* TODO: make sure we create an enum for it... */
193                 fprintf(out, "/* %s */int", symbol->string);
194                 return;
195         }
196         fprintf(out, "/* anonymous enum */int");
197 }
198
199 static void write_type(type_t *type)
200 {
201         type = skip_typeref(type);
202         switch(type->kind) {
203         case TYPE_ATOMIC:
204                 write_atomic_type(&type->atomic);
205                 return;
206         case TYPE_POINTER:
207                 write_pointer_type(&type->pointer);
208                 return;
209         case TYPE_COMPOUND_UNION:
210         case TYPE_COMPOUND_STRUCT:
211                 write_compound_type(&type->compound);
212                 return;
213         case TYPE_ENUM:
214                 write_enum_type(&type->enumt);
215                 return;
216         case TYPE_BUILTIN:
217                 write_type(type->builtin.real_type);
218                 return;
219         case TYPE_ERROR:
220         case TYPE_INVALID:
221         case TYPE_TYPEOF:
222         case TYPE_TYPEDEF:
223                 panic("invalid type found");
224         case TYPE_ARRAY:
225         case TYPE_BITFIELD:
226         case TYPE_REFERENCE:
227         case TYPE_FUNCTION:
228         case TYPE_COMPLEX:
229         case TYPE_IMAGINARY:
230                 fprintf(out, "/* TODO type */Pointer");
231                 break;
232         }
233 }
234
235 #if 0
236 static void write_compound_entry(const entity_t *entity)
237 {
238         fprintf(out, "\t%s : ", entity->base.symbol->string);
239         write_type(entity->declaration.type);
240         fprintf(out, "\n");
241 }
242
243 static void write_compound(const symbol_t *symbol, const compound_type_t *type)
244 {
245         fprintf(out, "%s %s:\n",
246                 type->base.kind == TYPE_COMPOUND_STRUCT ? "struct" : "union",
247                         symbol->string);
248
249         const entity_t *entity = type->compound->members.entities;
250         for ( ; entity != NULL; entity = entity->base.next) {
251                 write_compound_entry(entity);
252         }
253
254         fprintf(out, "\n");
255 }
256 #endif
257
258 static void write_expression(const expression_t *expression);
259
260 static void write_unary_expression(const unary_expression_t *expression)
261 {
262         switch(expression->base.kind) {
263         case EXPR_UNARY_NEGATE:
264                 fputc('-', out);
265                 break;
266         case EXPR_UNARY_NOT:
267                 fputc('!', out);
268                 break;
269         case EXPR_UNARY_CAST_IMPLICIT:
270                 write_expression(expression->value);
271                 return;
272         default:
273                 panic("unimeplemented unary expression found");
274         }
275         write_expression(expression->value);
276 }
277
278 static void write_binary_expression(const binary_expression_t *expression)
279 {
280         fputs("(", out);
281         write_expression(expression->left);
282         switch(expression->base.kind) {
283         case EXPR_BINARY_BITWISE_OR:  fputs("|", out); break;
284         case EXPR_BINARY_BITWISE_AND: fputs("&", out); break;
285         case EXPR_BINARY_BITWISE_XOR: fputs("^", out); break;
286         case EXPR_BINARY_SHIFTLEFT:   fputs("<<", out); break;
287         case EXPR_BINARY_SHIFTRIGHT:  fputs(">>", out); break;
288         case EXPR_BINARY_ADD:         fputs("+", out); break;
289         case EXPR_BINARY_SUB:         fputs("-", out); break;
290         case EXPR_BINARY_MUL:         fputs("*", out); break;
291         case EXPR_BINARY_DIV:         fputs("/", out); break;
292         default:
293                 panic("unimplemented binexpr");
294         }
295         write_expression(expression->right);
296         fputs(")", out);
297 }
298
299 static void write_expression(const expression_t *expression)
300 {
301         const const_expression_t *constant;
302         /* TODO */
303         switch(expression->kind) {
304         case EXPR_CONST:
305                 constant = &expression->conste;
306                 if(is_type_integer(expression->base.type)) {
307                         fprintf(out, "%lld", constant->v.int_value);
308                 } else {
309                         fprintf(out, "%Lf", constant->v.float_value);
310                 }
311                 break;
312         case EXPR_REFERENCE_ENUM_VALUE: {
313                 /* UHOH... hacking */
314                 entity_t *entity = expression->reference.entity;
315                 write_enum_name(& entity->enum_value.enum_type->enumt);
316                 fprintf(out, ".%s.val", entity->base.symbol->string);
317                 break;
318         }
319         EXPR_UNARY_CASES
320                 write_unary_expression(&expression->unary);
321                 break;
322         EXPR_BINARY_CASES
323                 write_binary_expression(&expression->binary);
324                 break;
325         default:
326                 panic("not implemented expression");
327         }
328 }
329
330 static void write_enum(const symbol_t *symbol, const enum_t *entity)
331 {
332         char buf[128];
333         const char *name;
334
335         if (symbol == NULL) {
336                 static int lastenum = 0;
337                 snprintf(buf, sizeof(buf), "AnonEnum%d", lastenum++);
338                 name = buf;
339         } else {
340                 name = symbol->string;
341         }
342
343         fprintf(out, "\tpublic static enum %s {\n", name);
344
345         entity_t *entry = entity->base.next;
346         for ( ; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
347                         entry = entry->base.next) {
348                 fprintf(out, "\t\t%s", entry->base.symbol->string);
349                 fprintf(out, "(");
350                 if(entry->enum_value.value != NULL) {
351                         write_expression(entry->enum_value.value);
352                 }
353                 fprintf(out, ")");
354                 if (entry->base.next != NULL
355                                 && entry->base.next->kind == ENTITY_ENUM_VALUE) {
356                         fputs(",\n", out);
357                 } else {
358                         fputs(";\n", out);
359                 }
360         }
361         fprintf(out, "\t\tpublic final int val;\n");
362         fprintf(out, "\t\tprivate static class C { static int next_val; }\n\n");
363         fprintf(out, "\t\t%s(int val) {\n", name);
364         fprintf(out, "\t\t\tthis.val = val;\n");
365         fprintf(out, "\t\t\tC.next_val = val + 1;\n");
366         fprintf(out, "\t\t}\n");
367         fprintf(out, "\t\t%s() {\n", name);
368         fprintf(out, "\t\t\tthis.val = C.next_val++;\n");
369         fprintf(out, "\t\t}\n");
370         fprintf(out, "\t\t\n");
371         fprintf(out, "\t\tpublic static %s getEnum(int val) {\n", name);
372         fprintf(out, "\t\t\tfor(%s entry : values()) {\n", name);
373         fprintf(out, "\t\t\t\tif (val == entry.val)\n");
374         fprintf(out, "\t\t\t\t\treturn entry;\n");
375         fprintf(out, "\t\t\t}\n");
376         fprintf(out, "\t\t\treturn null;\n");
377         fprintf(out, "\t\t}\n");
378         fprintf(out, "\t}\n");
379 }
380
381 #if 0
382 static void write_variable(const entity_t *entity)
383 {
384         fprintf(out, "var %s : ", entity->base.symbol->string);
385         write_type(entity->declaration.type);
386         fprintf(out, "\n");
387 }
388 #endif
389
390 static void write_function(const entity_t *entity)
391 {
392         if (entity->function.statement != NULL) {
393                 fprintf(stderr, "Warning: can't convert function bodies (at %s)\n",
394                         entity->base.symbol->string);
395                 return;
396         }
397
398
399         const function_type_t *function_type
400                 = (const function_type_t*) entity->declaration.type;
401
402         fputc('\t', out);
403         type_t *return_type = skip_typeref(function_type->return_type);
404         write_type(return_type);
405         fprintf(out, " %s(", entity->base.symbol->string);
406
407         entity_t *parameter = entity->function.parameters.entities;
408         int       first     = 1;
409         int       n         = 0;
410         for( ; parameter != NULL; parameter = parameter->base.next) {
411                 assert(parameter->kind == ENTITY_PARAMETER);
412                 if(!first) {
413                         fprintf(out, ", ");
414                 } else {
415                         first = 0;
416                 }
417                 write_type(parameter->declaration.type);
418                 if(parameter->base.symbol != NULL) {
419                         fprintf(out, " %s", fix_builtin_names(parameter->base.symbol->string));
420                 } else {
421                         fprintf(out, " _%d", n++);
422                 }
423         }
424         if(function_type->variadic) {
425                 if(!first) {
426                         fprintf(out, ", ");
427                 } else {
428                         first = 0;
429                 }
430                 fputs("Object ... args", out);
431         }
432         fprintf(out, ");\n");
433 }
434
435
436 void write_jna_decls(FILE *output, const translation_unit_t *unit)
437 {
438         out          = output;
439         global_scope = &unit->scope;
440
441         pset_new_init(&avoid_symbols);
442
443         print_to_file(out);
444         fprintf(out, "/* WARNING: Automatically generated file */\n");
445         fputs("import com.sun.jna.Library;\n", out);
446         fputs("import com.sun.jna.Pointer;\n", out);
447         fputs("\n\n", out);
448
449         /* TODO: where to get the name from? */
450         fputs("public interface binding extends Library {\n", out);
451
452         /* read the avoid list */
453         FILE *avoid = fopen("avoid.config", "r");
454         if (avoid != NULL) {
455                 while (!feof(avoid)) {
456                         char buf[1024];
457                         fgets(buf, sizeof(buf), avoid);
458                         size_t len = strlen(buf);
459                         if (buf[len-1] == '\n')
460                                 buf[len-1] = 0;
461                         if (buf[0] == 0)
462                                 continue;
463
464                         char *str = malloc(len+1);
465                         memcpy(str, buf, len+1);
466                         symbol_t *symbol = symbol_table_insert(str);
467                         pset_new_insert(&avoid_symbols, symbol);
468                 }
469                 fclose(avoid);
470         }
471
472         /* write structs,unions + enums */
473         entity_t *entity = unit->scope.entities;
474         for( ; entity != NULL; entity = entity->base.next) {
475                 if (entity->kind == ENTITY_ENUM) {
476                         if (find_enum_typedef(&entity->enume) != NULL)
477                                 continue;
478                         write_enum(entity->base.symbol, &entity->enume);
479                 } else if (entity->kind == ENTITY_TYPEDEF) {
480                         type_t *type = entity->typedefe.type;
481                         if (type->kind == TYPE_ENUM) {
482                                 write_enum(entity->base.symbol, type->enumt.enume);
483                         }
484                 }
485
486 #if 0
487                 if(type->kind == TYPE_COMPOUND_STRUCT
488                                 || type->kind == TYPE_COMPOUND_UNION) {
489                         write_compound(entity->base.symbol, &type->compound);
490                 }
491 #endif
492         }
493
494         /* write functions */
495         entity = unit->scope.entities;
496         for( ; entity != NULL; entity = entity->base.next) {
497                 if (entity->kind != ENTITY_FUNCTION)
498                         continue;
499                 if (is_system_header(entity->base.source_position.input_name))
500                         continue;
501
502                 if (pset_new_contains(&avoid_symbols, entity->base.symbol))
503                         continue;
504                 write_function(entity);
505         }
506
507         fputs("}\n", out);
508
509         pset_new_destroy(&avoid_symbols);
510 }