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