fix
[cparser] / wrappergen / write_caml.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_caml.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 "unit";
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         type_t *points_to = type->points_to;
70         if (points_to->kind == TYPE_ATOMIC &&
71                         is_type_atomic(points_to, ATOMIC_TYPE_CHAR)) {
72                 fputs("string", out);
73                 return;
74         }
75
76         write_type(type->points_to);
77         fputc('*', out);
78 }
79
80 static entity_t *find_typedef(const type_t *type)
81 {
82         /* first: search for a matching typedef in the global type... */
83         entity_t *entity = global_scope->entities;
84         for ( ; entity != NULL; entity = entity->base.next) {
85                 if (entity->kind != ENTITY_TYPEDEF)
86                         continue;
87                 if (entity->typedefe.type == type)
88                         break;
89         }
90
91         return entity;
92 }
93
94 static void write_compound_type(const compound_type_t *type)
95 {
96         const entity_t *entity = find_typedef((const type_t*) type);
97         if (entity != NULL) {
98                 fprintf(out, "%s", entity->base.symbol->string);
99                 return;
100         }
101
102         /* does the struct have a name? */
103         symbol_t *symbol = type->compound->base.symbol;
104         if (symbol != NULL) {
105                 /* TODO: make sure we create a struct for it... */
106                 fprintf(out, "%s", symbol->string);
107                 return;
108         }
109         /* TODO: create a struct and use its name here... */
110         fprintf(out, "/* TODO anonymous struct */byte");
111 }
112
113 static void write_enum_type(const enum_type_t *type)
114 {
115         const entity_t *entity = find_typedef((const type_t*) type);
116         if (entity != NULL) {
117                 fprintf(out, "%s", entity->base.symbol->string);
118                 return;
119         }
120
121         /* does the enum have a name? */
122         symbol_t *symbol = type->enume->base.symbol;
123         if (symbol != NULL) {
124                 /* TODO: make sure we create an enum for it... */
125                 fprintf(out, "%s", symbol->string);
126                 return;
127         }
128         /* TODO: create a struct and use its name here... */
129         fprintf(out, "/* TODO anonymous enum */byte");
130 }
131
132 static void write_function_type(const function_type_t *type)
133 {
134         fprintf(out, "(func(");
135
136         function_parameter_t *parameter = type->parameters;
137         int                   first     = 1;
138         while(parameter != NULL) {
139                 if (!first) {
140                         fprintf(out, ", ");
141                 } else {
142                         first = 0;
143                 }
144
145 #if 0
146                 if (parameter->symbol != NULL) {
147                         fprintf(out, "%s : ", parameter->symbol->string);
148                 } else {
149                         /* TODO make up some unused names (or allow _ in fluffy?) */
150                         fprintf(out, "_ : ");
151                 }
152 #endif
153                 fputs("_ : ", out);
154                 write_type(parameter->type);
155
156                 parameter = parameter->next;
157         }
158
159         fprintf(out, ") : ");
160         write_type(type->return_type);
161         fprintf(out, ")");
162 }
163
164 static void write_type(const type_t *type)
165 {
166         switch(type->kind) {
167         case TYPE_ATOMIC:
168                 write_atomic_type(&type->atomic);
169                 return;
170         case TYPE_POINTER:
171                 write_pointer_type(&type->pointer);
172                 return;
173         case TYPE_COMPOUND_UNION:
174         case TYPE_COMPOUND_STRUCT:
175                 write_compound_type(&type->compound);
176                 return;
177         case TYPE_ENUM:
178                 write_enum_type(&type->enumt);
179                 return;
180         case TYPE_FUNCTION:
181                 write_function_type(&type->function);
182                 return;
183         case TYPE_INVALID:
184                 panic("invalid type found");
185         case TYPE_COMPLEX:
186         case TYPE_IMAGINARY:
187         default:
188                 fprintf(out, "/* TODO type */");
189                 break;
190         }
191 }
192
193 static void write_function(const entity_t *entity)
194 {
195         if (entity->function.statement != NULL) {
196                 fprintf(stderr, "Warning: can't convert function bodies (at %s)\n",
197                         entity->base.symbol->string);
198         }
199
200         fprintf(out, "external %s: ", entity->base.symbol->string);
201
202         const function_type_t *function_type
203                 = (const function_type_t*) entity->declaration.type;
204
205         entity_t *parameter = entity->function.parameters.entities;
206         for( ; parameter != NULL; parameter = parameter->base.next) {
207                 assert(parameter->kind == ENTITY_PARAMETER);
208                 write_type(parameter->declaration.type);
209                 fputs(" -> ", out);
210         }
211         if (function_type->variadic) {
212                 fprintf(stderr, "WARNING: Variadic function not supported yet\n");
213         }
214         if (function_type->unspecified_parameters) {
215                 fprintf(stderr, "WARNING: unspecified params not supported\n");
216         }
217         const type_t *return_type = function_type->return_type;
218         write_type(return_type);
219
220         fputs(" = \"", out);
221         fputs(entity->base.symbol->string, out);
222         fputs("\"", out);
223
224         fputc('\n', out);
225 }
226
227 void write_caml_decls(FILE *output, const translation_unit_t *unit)
228 {
229         out          = output;
230         global_scope = &unit->scope;
231
232         print_to_file(out);
233         fprintf(out, "(* WARNING: Automatically generated file - chaning is useless *)\n");
234
235         /* write functions */
236         entity_t *entity = unit->scope.entities;
237         for( ; entity != NULL; entity = entity->base.next) {
238                 if (entity->kind != ENTITY_FUNCTION)
239                         continue;
240
241                 write_function(entity);
242         }
243 }