fix a bunch of warnings (reported by cparser)
[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 "adt/xmalloc.h"
34 #include <libfirm/adt/pset_new.h>
35
36 typedef struct output_limit {
37         const char          *filename;
38         struct output_limit *next;
39 } output_limit;
40
41 static const scope_t *global_scope;
42 static FILE          *out;
43 static pset_new_t     avoid_symbols;
44 static output_limit  *output_limits;
45 static const char    *libname;
46
47 static bool is_system_header(const char *fname)
48 {
49         if (strncmp(fname, "/usr/include", 12) == 0)
50                 return true;
51         if (fname == builtin_source_position.input_name)
52                 return true;
53         return false;
54 }
55
56 static const char *fix_builtin_names(const char *name)
57 {
58         if (strcmp(name, "class") == 0) {
59                 return "_class";
60         } else if(strcmp(name, "this") == 0) {
61                 return "_this";
62         } else if(strcmp(name, "public") == 0) {
63                 return "_public";
64         } else if(strcmp(name, "protected") == 0) {
65                 return "_protected";
66         } else if(strcmp(name, "private") == 0) {
67                 return "_private";
68         } else if(strcmp(name, "final") == 0) {
69                 return "_final";
70         }
71         /* TODO put all reserved names here */
72         return name;
73 }
74
75 static const char *get_atomic_type_string(const atomic_type_kind_t type)
76 {
77         switch(type) {
78         case ATOMIC_TYPE_VOID:        return "void";
79         case ATOMIC_TYPE_CHAR:        return "byte";
80         case ATOMIC_TYPE_SCHAR:       return "byte";
81         case ATOMIC_TYPE_UCHAR:       return "byte";
82         case ATOMIC_TYPE_SHORT:       return "short";
83         case ATOMIC_TYPE_USHORT:      return "short";
84         case ATOMIC_TYPE_INT:         return "int";
85         case ATOMIC_TYPE_UINT:        return "int";
86         case ATOMIC_TYPE_LONG:        return "com.sun.jna.NativeLong";
87         case ATOMIC_TYPE_ULONG:       return "com.sun.jna.NativeLong";
88         case ATOMIC_TYPE_LONGLONG:    return "long";
89         case ATOMIC_TYPE_ULONGLONG:   return "long";
90         case ATOMIC_TYPE_FLOAT:       return "float";
91         case ATOMIC_TYPE_DOUBLE:      return "double";
92         case ATOMIC_TYPE_BOOL:        return "boolean";
93         default:                      panic("unsupported atomic type");
94         }
95 }
96
97 static void write_atomic_type(const atomic_type_t *type)
98 {
99         fputs(get_atomic_type_string(type->akind), out);
100 }
101
102 static void write_pointer_type(const pointer_type_t *type)
103 {
104         type_t *points_to = skip_typeref(type->points_to);
105         if (is_type_atomic(points_to, ATOMIC_TYPE_CHAR)) {
106                 fputs("String", out);
107                 return;
108         }
109         if (is_type_pointer(points_to)) {
110                 /* hack... */
111                 fputs("java.nio.Buffer", out);
112                 return;
113         }
114         fputs("Pointer", out);
115 }
116
117 static entity_t *find_typedef(const type_t *type)
118 {
119         /* first: search for a matching typedef in the global type... */
120         entity_t *entity = global_scope->entities;
121         for ( ; entity != NULL; entity = entity->base.next) {
122                 if (entity->kind != ENTITY_TYPEDEF)
123                         continue;
124                 if (entity->typedefe.type == type)
125                         break;
126         }
127
128         return entity;
129 }
130
131 static entity_t *find_enum_typedef(const enum_t *enume)
132 {
133         /* first: search for a matching typedef in the global type... */
134         entity_t *entity = global_scope->entities;
135         for ( ; entity != NULL; entity = entity->base.next) {
136                 if (entity->kind != ENTITY_TYPEDEF)
137                         continue;
138                 type_t *type = entity->typedefe.type;
139                 if (type->kind != TYPE_ENUM)
140                         continue;
141
142                 enum_t *e_entity = type->enumt.enume;
143                 if (e_entity == enume)
144                         break;
145         }
146
147         return entity;
148 }
149
150 static void write_compound_type(const compound_type_t *type)
151 {
152         entity_t *entity = find_typedef((const type_t*) type);
153         if(entity != NULL) {
154                 fputs(entity->base.symbol->string, out);
155                 return;
156         }
157
158         /* does the struct have a name? */
159         symbol_t *symbol = type->compound->base.symbol;
160         if(symbol != NULL) {
161                 /* TODO: make sure we create a struct for it... */
162                 fputs(symbol->string, out);
163                 return;
164         }
165         /* TODO: create a struct and use its name here... */
166         fputs("/* TODO anonymous struct */byte", out);
167 }
168
169 static void write_enum_name(const enum_type_t *type)
170 {
171         entity_t *entity = find_typedef((const type_t*) type);
172         if (entity != NULL) {
173                 fputs(entity->base.symbol->string, out);
174                 return;
175         }
176
177         /* does the enum have a name? */
178         symbol_t *symbol = type->enume->base.symbol;
179         if (symbol != NULL) {
180                 /* TODO: make sure we create an enum for it... */
181                 fputs(symbol->string, out);
182                 return;
183         }
184
185         /* now we have a problem as we don't know how we'll call the anonymous
186          * enum */
187         panic("can't reference entries from anonymous enums yet");
188 }
189
190 static void write_enum_type(const enum_type_t *type)
191 {
192         entity_t *entity = find_typedef((const type_t*) type);
193         if (entity != NULL) {
194                 fprintf(out, "/* %s */int", entity->base.symbol->string);
195                 return;
196         }
197
198         /* does the enum have a name? */
199         symbol_t *symbol = type->enume->base.symbol;
200         if (symbol != NULL) {
201                 /* TODO: make sure we create an enum for it... */
202                 fprintf(out, "/* %s */int", symbol->string);
203                 return;
204         }
205         fprintf(out, "/* anonymous enum */int");
206 }
207
208 static void write_type(type_t *type)
209 {
210         type = skip_typeref(type);
211         switch(type->kind) {
212         case TYPE_ATOMIC:
213                 write_atomic_type(&type->atomic);
214                 return;
215         case TYPE_POINTER:
216                 write_pointer_type(&type->pointer);
217                 return;
218         case TYPE_COMPOUND_UNION:
219         case TYPE_COMPOUND_STRUCT:
220                 write_compound_type(&type->compound);
221                 return;
222         case TYPE_ENUM:
223                 write_enum_type(&type->enumt);
224                 return;
225         case TYPE_ERROR:
226         case TYPE_INVALID:
227         case TYPE_TYPEOF:
228         case TYPE_TYPEDEF:
229                 panic("invalid type found");
230         case TYPE_ARRAY:
231         case TYPE_BITFIELD:
232         case TYPE_REFERENCE:
233         case TYPE_FUNCTION:
234         case TYPE_COMPLEX:
235         case TYPE_IMAGINARY:
236                 fprintf(out, "/* TODO type */Pointer");
237                 break;
238         }
239 }
240
241 #if 0
242 static void write_compound_entry(const entity_t *entity)
243 {
244         fprintf(out, "\t%s : ", entity->base.symbol->string);
245         write_type(entity->declaration.type);
246         fprintf(out, "\n");
247 }
248
249 static void write_compound(const symbol_t *symbol, const compound_type_t *type)
250 {
251         fprintf(out, "%s %s:\n",
252                 type->base.kind == TYPE_COMPOUND_STRUCT ? "struct" : "union",
253                         symbol->string);
254
255         const entity_t *entity = type->compound->members.entities;
256         for ( ; entity != NULL; entity = entity->base.next) {
257                 write_compound_entry(entity);
258         }
259
260         fprintf(out, "\n");
261 }
262 #endif
263
264 static void write_expression(const expression_t *expression);
265
266 static void write_unary_expression(const unary_expression_t *expression)
267 {
268         switch(expression->base.kind) {
269         case EXPR_UNARY_NEGATE:
270                 fputc('-', out);
271                 break;
272         case EXPR_UNARY_NOT:
273                 fputc('!', out);
274                 break;
275         case EXPR_UNARY_CAST_IMPLICIT:
276                 write_expression(expression->value);
277                 return;
278         default:
279                 panic("unimeplemented unary expression found");
280         }
281         write_expression(expression->value);
282 }
283
284 static void write_binary_expression(const binary_expression_t *expression)
285 {
286         fputs("(", out);
287         write_expression(expression->left);
288         fputc(' ', out);
289         switch(expression->base.kind) {
290         case EXPR_BINARY_BITWISE_OR:  fputs("|", out); break;
291         case EXPR_BINARY_BITWISE_AND: fputs("&", out); break;
292         case EXPR_BINARY_BITWISE_XOR: fputs("^", out); break;
293         case EXPR_BINARY_SHIFTLEFT:   fputs("<<", out); break;
294         case EXPR_BINARY_SHIFTRIGHT:  fputs(">>", out); break;
295         case EXPR_BINARY_ADD:         fputs("+", out); break;
296         case EXPR_BINARY_SUB:         fputs("-", out); break;
297         case EXPR_BINARY_MUL:         fputs("*", out); break;
298         case EXPR_BINARY_DIV:         fputs("/", out); break;
299         default:
300                 panic("unimplemented binexpr");
301         }
302         fputc(' ', out);
303         write_expression(expression->right);
304         fputs(")", out);
305 }
306
307 static void write_expression(const expression_t *expression)
308 {
309         /* TODO */
310         switch(expression->kind) {
311         case EXPR_LITERAL_INTEGER:
312         case EXPR_LITERAL_INTEGER_OCTAL:
313                 fprintf(out, "%s", expression->literal.value.begin);
314                 break;
315         case EXPR_LITERAL_INTEGER_HEXADECIMAL:
316                 fprintf(out, "0x%s", expression->literal.value.begin);
317                 break;
318         case EXPR_REFERENCE_ENUM_VALUE: {
319                 /* UHOH... hacking */
320                 entity_t *entity = expression->reference.entity;
321                 write_enum_name(& entity->enum_value.enum_type->enumt);
322                 fprintf(out, ".%s.val", entity->base.symbol->string);
323                 break;
324         }
325         EXPR_UNARY_CASES
326                 write_unary_expression(&expression->unary);
327                 break;
328         EXPR_BINARY_CASES
329                 write_binary_expression(&expression->binary);
330                 break;
331         default:
332                 panic("not implemented expression");
333         }
334 }
335
336 static void write_enum(const symbol_t *symbol, const enum_t *entity)
337 {
338         char buf[128];
339         const char *name;
340
341         if (symbol == NULL) {
342                 static int lastenum = 0;
343                 snprintf(buf, sizeof(buf), "AnonEnum%d", lastenum++);
344                 name = buf;
345         } else {
346                 name = symbol->string;
347         }
348
349         fprintf(out, "\tpublic static enum %s {\n", name);
350
351         entity_t *entry = entity->base.next;
352         for ( ; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
353                         entry = entry->base.next) {
354                 fprintf(out, "\t\t%s", entry->base.symbol->string);
355                 fprintf(out, "(");
356                 if(entry->enum_value.value != NULL) {
357                         write_expression(entry->enum_value.value);
358                 }
359                 fprintf(out, ")");
360                 if (entry->base.next != NULL
361                                 && entry->base.next->kind == ENTITY_ENUM_VALUE) {
362                         fputs(",\n", out);
363                 } else {
364                         fputs(";\n", out);
365                 }
366         }
367         fprintf(out, "\t\tpublic final int val;\n");
368         fprintf(out, "\n");
369         fprintf(out, "\t\tprivate static class C {\n");
370         fprintf(out, "\t\t\tstatic int next_val;\n");
371         fprintf(out, "\t\t}\n");
372         fprintf(out, "\n");
373         fprintf(out, "\t\t%s(int val) {\n", name);
374         fprintf(out, "\t\t\tthis.val = val;\n");
375         fprintf(out, "\t\t\tC.next_val = val + 1;\n");
376         fprintf(out, "\t\t}\n");
377         fprintf(out, "\n");
378         fprintf(out, "\t\t%s() {\n", name);
379         fprintf(out, "\t\t\tthis.val = C.next_val++;\n");
380         fprintf(out, "\t\t}\n");
381         fprintf(out, "\n");
382         fprintf(out, "\t\tpublic static %s getEnum(int val) {\n", name);
383         fprintf(out, "\t\t\tfor (%s entry : values()) {\n", name);
384         fprintf(out, "\t\t\t\tif (val == entry.val)\n");
385         fprintf(out, "\t\t\t\t\treturn entry;\n");
386         fprintf(out, "\t\t\t}\n");
387         fprintf(out, "\t\t\treturn null;\n");
388         fprintf(out, "\t\t}\n");
389         fprintf(out, "\t}\n");
390         fprintf(out, "\n");
391 }
392
393 #if 0
394 static void write_variable(const entity_t *entity)
395 {
396         fprintf(out, "var %s : ", entity->base.symbol->string);
397         write_type(entity->declaration.type);
398         fprintf(out, "\n");
399 }
400 #endif
401
402 static void write_function(const entity_t *entity)
403 {
404         if (entity->function.statement != NULL) {
405                 fprintf(stderr, "Warning: can't convert function bodies (at %s)\n",
406                         entity->base.symbol->string);
407                 return;
408         }
409
410
411         const function_type_t *function_type
412                 = (const function_type_t*) entity->declaration.type;
413
414         fputc('\n', out);
415         fprintf(out, "\tpublic static native ");
416         type_t *return_type = skip_typeref(function_type->return_type);
417         write_type(return_type);
418         fprintf(out, " %s(", entity->base.symbol->string);
419
420         entity_t *parameter = entity->function.parameters.entities;
421         int       first     = 1;
422         int       n         = 0;
423         for ( ; parameter != NULL; parameter = parameter->base.next) {
424                 assert(parameter->kind == ENTITY_PARAMETER);
425                 if(!first) {
426                         fprintf(out, ", ");
427                 } else {
428                         first = 0;
429                 }
430                 write_type(parameter->declaration.type);
431                 if(parameter->base.symbol != NULL) {
432                         fprintf(out, " %s", fix_builtin_names(parameter->base.symbol->string));
433                 } else {
434                         fprintf(out, " _%d", n++);
435                 }
436         }
437         if(function_type->variadic) {
438                 if(!first) {
439                         fprintf(out, ", ");
440                 } else {
441                         first = 0;
442                 }
443                 fputs("Object ... args", out);
444         }
445         fprintf(out, ");\n");
446 }
447
448 void jna_limit_output(const char *filename)
449 {
450         output_limit *limit = xmalloc(sizeof(limit[0]));
451         limit->filename = filename;
452
453         limit->next   = output_limits;
454         output_limits = limit;
455 }
456
457 void jna_set_libname(const char *new_libname)
458 {
459         libname = new_libname;
460 }
461
462 void write_jna_decls(FILE *output, const translation_unit_t *unit)
463 {
464         out          = output;
465         global_scope = &unit->scope;
466
467         pset_new_init(&avoid_symbols);
468
469         print_to_file(out);
470         fprintf(out, "/* WARNING: Automatically generated file */\n");
471         fputs("import com.sun.jna.Native;\n", out);
472         fputs("import com.sun.jna.Pointer;\n", out);
473         fputs("\n", out);
474
475         const char *register_libname = libname;
476         if (register_libname == NULL)
477                 register_libname = "library";
478
479         /* TODO: where to get the name from? */
480         fputs("public class binding {\n", out);
481         fputs("\tstatic {\n", out);
482         fprintf(out, "\t\tNative.register(\"%s\");\n", register_libname);
483         fputs("\t}\n", out);
484         fputs("\n", out);
485
486         /* read the avoid list */
487         FILE *avoid = fopen("avoid.config", "r");
488         if (avoid != NULL) {
489                 while (!feof(avoid)) {
490                         char buf[1024];
491                         char *res = fgets(buf, sizeof(buf), avoid);
492                         if (res == NULL)
493                                 break;
494                         if (buf[0] == 0)
495                                 continue;
496
497                         size_t len = strlen(buf);
498                         if (buf[len-1] == '\n')
499                                 buf[len-1] = 0;
500
501                         char *str = malloc(len+1);
502                         memcpy(str, buf, len+1);
503                         symbol_t *symbol = symbol_table_insert(str);
504                         pset_new_insert(&avoid_symbols, symbol);
505                 }
506                 fclose(avoid);
507         }
508
509         /* write structs,unions + enums */
510         entity_t *entity = unit->scope.entities;
511         for ( ; entity != NULL; entity = entity->base.next) {
512                 if (entity->kind == ENTITY_ENUM) {
513                         if (find_enum_typedef(&entity->enume) != NULL)
514                                 continue;
515                         write_enum(entity->base.symbol, &entity->enume);
516                 } else if (entity->kind == ENTITY_TYPEDEF) {
517                         type_t *type = entity->typedefe.type;
518                         if (type->kind == TYPE_ENUM) {
519                                 write_enum(entity->base.symbol, type->enumt.enume);
520                         }
521                 }
522
523 #if 0
524                 if(type->kind == TYPE_COMPOUND_STRUCT
525                                 || type->kind == TYPE_COMPOUND_UNION) {
526                         write_compound(entity->base.symbol, &type->compound);
527                 }
528 #endif
529         }
530
531         /* write functions */
532         entity = unit->scope.entities;
533         for ( ; entity != NULL; entity = entity->base.next) {
534                 if (entity->kind != ENTITY_FUNCTION)
535                         continue;
536                 const char *input_name = entity->base.source_position.input_name;
537                 if (is_system_header(input_name))
538                         continue;
539                 if (entity->function.elf_visibility != ELF_VISIBILITY_DEFAULT)
540                         continue;
541                 if (output_limits != NULL) {
542                         bool in_limits = false;
543                         for (output_limit *limit = output_limits; limit != NULL;
544                              limit = limit->next) {
545                             if (strcmp(limit->filename, input_name) == 0) {
546                                         in_limits = true;
547                                         break;
548                                 }
549                         }
550                         if (!in_limits)
551                                 continue;
552                 }
553
554                 if (pset_new_contains(&avoid_symbols, entity->base.symbol))
555                         continue;
556                 write_function(entity);
557         }
558
559         fputs("}\n", out);
560
561         pset_new_destroy(&avoid_symbols);
562 }