clang static analyzer warning fixes
[cparser] / wrappergen / write_fluffy.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_fluffy.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 "adt/error.h"
32 #include "printer.h"
33
34 static const scope_t *global_scope;
35 static FILE          *out;
36
37 static void write_type(const type_t *type);
38
39 static const char *get_atomic_type_string(const atomic_type_kind_t type)
40 {
41         switch(type) {
42         case ATOMIC_TYPE_VOID:        return "void";
43         case ATOMIC_TYPE_CHAR:        return "byte";
44         case ATOMIC_TYPE_SCHAR:       return "byte";
45         case ATOMIC_TYPE_UCHAR:       return "unsigned byte";
46         case ATOMIC_TYPE_SHORT:       return "short";
47         case ATOMIC_TYPE_USHORT:      return "unsigned short";
48         case ATOMIC_TYPE_INT:         return "int";
49         case ATOMIC_TYPE_UINT:        return "unsigned int";
50         case ATOMIC_TYPE_LONG:        return "int";
51         case ATOMIC_TYPE_ULONG:       return "unsigned int";
52         case ATOMIC_TYPE_LONGLONG:    return "long";
53         case ATOMIC_TYPE_ULONGLONG:   return "unsigned long";
54         case ATOMIC_TYPE_FLOAT:       return "float";
55         case ATOMIC_TYPE_DOUBLE:      return "double";
56         case ATOMIC_TYPE_LONG_DOUBLE: return "double";
57         case ATOMIC_TYPE_BOOL:        return "bool";
58         default:                      panic("unsupported atomic type");
59         }
60 }
61
62 static void write_atomic_type(const atomic_type_t *type)
63 {
64         fprintf(out, "%s", get_atomic_type_string(type->akind));
65 }
66
67 static void write_pointer_type(const pointer_type_t *type)
68 {
69         write_type(type->points_to);
70         fputc('*', out);
71 }
72
73 static entity_t *find_typedef(const type_t *type)
74 {
75         /* first: search for a matching typedef in the global type... */
76         entity_t *entity = global_scope->entities;
77         for ( ; entity != NULL; entity = entity->base.next) {
78                 if (entity->kind != ENTITY_TYPEDEF)
79                         continue;
80                 if (entity->typedefe.type == type)
81                         break;
82         }
83
84         return entity;
85 }
86
87 static void write_compound_type(const compound_type_t *type)
88 {
89         entity_t *entity = find_typedef((const type_t*) type);
90         if(entity != NULL) {
91                 fprintf(out, "%s", entity->base.symbol->string);
92                 return;
93         }
94
95         /* does the struct have a name? */
96         symbol_t *symbol = type->compound->base.symbol;
97         if(symbol != NULL) {
98                 /* TODO: make sure we create a struct for it... */
99                 fprintf(out, "%s", symbol->string);
100                 return;
101         }
102         /* TODO: create a struct and use its name here... */
103         fprintf(out, "/* TODO anonymous struct */byte");
104 }
105
106 static void write_enum_type(const enum_type_t *type)
107 {
108         entity_t *entity = find_typedef((const type_t*) type);
109         if (entity != NULL) {
110                 fprintf(out, "%s", entity->base.symbol->string);
111                 return;
112         }
113
114         /* does the enum have a name? */
115         symbol_t *symbol = type->enume->base.symbol;
116         if (symbol != NULL) {
117                 /* TODO: make sure we create an enum for it... */
118                 fprintf(out, "%s", symbol->string);
119                 return;
120         }
121         /* TODO: create a struct and use its name here... */
122         fprintf(out, "/* TODO anonymous enum */byte");
123 }
124
125 static void write_function_type(const function_type_t *type)
126 {
127         fprintf(out, "(func(");
128
129         function_parameter_t *parameter = type->parameters;
130         int                   first     = 1;
131         while(parameter != NULL) {
132                 if(!first) {
133                         fprintf(out, ", ");
134                 } else {
135                         first = 0;
136                 }
137
138 #if 0
139                 if(parameter->symbol != NULL) {
140                         fprintf(out, "%s : ", parameter->symbol->string);
141                 } else {
142                         /* TODO make up some unused names (or allow _ in fluffy?) */
143                         fprintf(out, "_ : ");
144                 }
145 #endif
146                 fputs("_ : ", out);
147                 write_type(parameter->type);
148
149                 parameter = parameter->next;
150         }
151
152         fprintf(out, ") : ");
153         write_type(type->return_type);
154         fprintf(out, ")");
155 }
156
157 static void write_type(const type_t *type)
158 {
159         switch(type->kind) {
160         case TYPE_ATOMIC:
161                 write_atomic_type(&type->atomic);
162                 return;
163         case TYPE_POINTER:
164                 write_pointer_type(&type->pointer);
165                 return;
166         case TYPE_COMPOUND_UNION:
167         case TYPE_COMPOUND_STRUCT:
168                 write_compound_type(&type->compound);
169                 return;
170         case TYPE_ENUM:
171                 write_enum_type(&type->enumt);
172                 return;
173         case TYPE_FUNCTION:
174                 write_function_type(&type->function);
175                 return;
176         case TYPE_COMPLEX:
177         case TYPE_IMAGINARY:
178         default:
179                 fprintf(out, "/* TODO type */");
180                 break;
181         }
182 }
183
184 static void write_compound_entry(const entity_t *entity)
185 {
186         fprintf(out, "\t%s : ", entity->base.symbol->string);
187         write_type(entity->declaration.type);
188         fprintf(out, "\n");
189 }
190
191 static void write_compound(const symbol_t *symbol, const compound_type_t *type)
192 {
193         fprintf(out, "%s %s:\n",
194                 type->base.kind == TYPE_COMPOUND_STRUCT ? "struct" : "union",
195                         symbol->string);
196
197         const entity_t *entity = type->compound->members.entities;
198         for ( ; entity != NULL; entity = entity->base.next) {
199                 write_compound_entry(entity);
200         }
201
202         fprintf(out, "\n");
203 }
204
205 static void write_expression(const expression_t *expression);
206
207 static void write_unary_expression(const unary_expression_t *expression)
208 {
209         switch(expression->base.kind) {
210         case EXPR_UNARY_NEGATE:
211                 fputc('-', out);
212                 break;
213         case EXPR_UNARY_NOT:
214                 fputc('!', out);
215                 break;
216         default:
217                 panic("unimeplemented unary expression found");
218         }
219         write_expression(expression->value);
220 }
221
222 static void write_expression(const expression_t *expression)
223 {
224         switch(expression->kind) {
225         case EXPR_LITERAL_INTEGER:
226                 fprintf(out, "%s", expression->literal.value.begin);
227                 break;
228         case EXPR_UNARY_CASES:
229                 write_unary_expression((const unary_expression_t*) expression);
230                 break;
231         default:
232                 panic("not implemented expression");
233         }
234 }
235
236 static void write_enum(const symbol_t *symbol, const enum_type_t *type)
237 {
238         fprintf(out, "enum %s:\n", symbol->string);
239
240         entity_t *entry = type->enume->base.next;
241         for ( ; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
242                         entry = entry->base.next) {
243                 fprintf(out, "\t%s", entry->base.symbol->string);
244                 if(entry->enum_value.value != NULL) {
245                         fprintf(out, " <- ");
246                         write_expression(entry->enum_value.value);
247                 }
248                 fputc('\n', out);
249         }
250         fprintf(out, "typealias %s <- int\n", symbol->string);
251         fprintf(out, "\n");
252 }
253
254 static void write_variable(const entity_t *entity)
255 {
256         fprintf(out, "var %s : ", entity->base.symbol->string);
257         write_type(entity->declaration.type);
258         fprintf(out, "\n");
259 }
260
261 static void write_function(const entity_t *entity)
262 {
263         if (entity->function.body != NULL) {
264                 fprintf(stderr, "Warning: can't convert function bodies (at %s)\n",
265                         entity->base.symbol->string);
266         }
267
268         fprintf(out, "func extern %s(", entity->base.symbol->string);
269
270         const function_type_t *function_type
271                 = (const function_type_t*) entity->declaration.type;
272
273         entity_t *parameter = entity->function.parameters.entities;
274         int       first     = 1;
275         for( ; parameter != NULL; parameter = parameter->base.next) {
276                 assert(parameter->kind == ENTITY_PARAMETER);
277                 if(!first) {
278                         fprintf(out, ", ");
279                 } else {
280                         first = 0;
281                 }
282                 if(parameter->base.symbol != NULL) {
283                         fprintf(out, "%s : ", parameter->base.symbol->string);
284                 } else {
285                         fputs("_ : ", out);
286                 }
287                 write_type(parameter->declaration.type);
288         }
289         if(function_type->variadic) {
290                 if(!first) {
291                         fprintf(out, ", ");
292                 }
293                 fputs("...", out);
294         }
295         fprintf(out, ")");
296
297         const type_t *return_type = skip_typeref(function_type->return_type);
298         if (!is_type_void(return_type)) {
299                 fprintf(out, " : ");
300                 write_type(return_type);
301         }
302         fputc('\n', out);
303 }
304
305 void write_fluffy_decls(FILE *output, const translation_unit_t *unit)
306 {
307         out            = output;
308         global_scope = &unit->scope;
309
310         print_to_file(out);
311         fprintf(out, "/* WARNING: Automatically generated file */\n");
312
313         /* write structs,unions + enums */
314         entity_t *entity = unit->scope.entities;
315         for( ; entity != NULL; entity = entity->base.next) {
316                 if (entity->kind != ENTITY_TYPEDEF)
317                         continue;
318
319                 type_t *type = entity->typedefe.type;
320                 if (is_type_compound(type)) {
321                         write_compound(entity->base.symbol, &type->compound);
322                 } else if(type->kind == TYPE_ENUM) {
323                         write_enum(entity->base.symbol, &type->enumt);
324                 }
325         }
326
327         /* write global variables */
328         entity = unit->scope.entities;
329         for( ; entity != NULL; entity = entity->base.next) {
330                 if (entity->kind != ENTITY_VARIABLE)
331                         continue;
332
333                 write_variable(entity);
334         }
335
336         /* write functions */
337         entity = unit->scope.entities;
338         for( ; entity != NULL; entity = entity->base.next) {
339                 if (entity->kind != ENTITY_FUNCTION)
340                         continue;
341
342                 write_function(entity);
343         }
344 }