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