1 /* duktape binding generation implementation
2 *
3 * This file is part of nsgenbind.
4 * Licensed under the MIT License,
5 * http://www.opensource.org/licenses/mit-license.php
6 * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdbool.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <getopt.h>
15 #include <errno.h>
16 #include <ctype.h>
17
18 #include "options.h"
19 #include "utils.h"
20 #include "nsgenbind-ast.h"
21 #include "webidl-ast.h"
22 #include "ir.h"
23 #include "output.h"
24 #include "duk-libdom.h"
25
26 /** prefix for all generated functions */
27 #define DLPFX "dukky"
28
29 #define MAGICPFX "\\xFF\\xFFNETSURF_DUKTAPE_"
30
31
32 /**
33 * get default value as a string
34 */
35 static int
get_member_default_str(struct ir_entry * dictionarye,struct ir_operation_argument_entry * membere,enum webidl_type member_type,char ** defl_out)36 get_member_default_str(struct ir_entry *dictionarye,
37 struct ir_operation_argument_entry *membere,
38 enum webidl_type member_type,
39 char **defl_out)
40 {
41 struct webidl_node *lit_node;
42 enum webidl_node_type lit_type;
43 int *lit_int;
44 float *lit_flt;
45
46 lit_node = webidl_node_getnode(
47 webidl_node_find_type(
48 webidl_node_getnode(membere->node),
49 NULL,
50 WEBIDL_NODE_TYPE_OPTIONAL));
51 if (lit_node == NULL) {
52 *defl_out = NULL;
53 return 0;
54 }
55
56 lit_type = webidl_node_gettype(lit_node);
57
58 switch (lit_type) {
59
60 case WEBIDL_NODE_TYPE_LITERAL_BOOL:
61 if (member_type != WEBIDL_TYPE_BOOL) {
62 fprintf(stderr,
63 "Dictionary %s:%s literal boolean type mismatch\n",
64 dictionarye->name,
65 membere->name);
66 return -1;
67 }
68 lit_int = webidl_node_getint(lit_node);
69 if (*lit_int == 0) {
70 *defl_out = strdup("false");
71 } else {
72 *defl_out = strdup("true");
73 }
74 break;
75
76 case WEBIDL_NODE_TYPE_LITERAL_NULL:
77 *defl_out = strdup("NULL");
78 break;
79
80 case WEBIDL_NODE_TYPE_LITERAL_STRING:
81 *defl_out = strdup(webidl_node_gettext(lit_node));
82 break;
83
84 case WEBIDL_NODE_TYPE_LITERAL_INT:
85 lit_int = webidl_node_getint(lit_node);
86 *defl_out = malloc(128);
87 snprintf(*defl_out, 128, "%d", *lit_int);
88 break;
89
90 case WEBIDL_NODE_TYPE_LITERAL_FLOAT:
91 lit_flt = webidl_node_getfloat(lit_node);
92 *defl_out = malloc(128);
93 snprintf(*defl_out, 128, "%f", *lit_flt);
94 break;
95
96 default:
97 *defl_out = NULL;
98 break;
99 }
100
101 return 0;
102 }
103
104
105 /**
106 * generate a single class method for an interface operation
107 */
108 static int
output_member_acessor(struct opctx * outc,struct ir_entry * dictionarye,struct ir_operation_argument_entry * membere)109 output_member_acessor(struct opctx *outc,
110 struct ir_entry *dictionarye,
111 struct ir_operation_argument_entry *membere)
112 {
113 struct webidl_node *type_node;
114 enum webidl_type *argument_type;
115 char *defl; /* default for member */
116 int res;
117
118 type_node = webidl_node_find_type(
119 webidl_node_getnode(membere->node),
120 NULL,
121 WEBIDL_NODE_TYPE_TYPE);
122
123 if (type_node == NULL) {
124 fprintf(stderr, "%s:%s has no type\n",
125 dictionarye->name,
126 membere->name);
127 return -1;
128 }
129
130 argument_type = (enum webidl_type *)webidl_node_getint(
131 webidl_node_find_type(
132 webidl_node_getnode(type_node),
133 NULL,
134 WEBIDL_NODE_TYPE_TYPE_BASE));
135
136 if (argument_type == NULL) {
137 fprintf(stderr,
138 "%s:%s has no type base\n",
139 dictionarye->name,
140 membere->name);
141 return -1;
142 }
143
144 /* get default text */
145 res = get_member_default_str(dictionarye, membere, *argument_type, &defl);
146 if (res != 0) {
147 return res;
148 }
149
150 switch (*argument_type) {
151
152 case WEBIDL_TYPE_STRING:
153 outputf(outc,
154 "const char *\n"
155 "%s_%s_get_%s(duk_context *ctx, duk_idx_t idx)\n"
156 "{\n",
157 DLPFX, dictionarye->class_name, membere->name);
158
159 if (defl == NULL) {
160 outputf(outc,
161 "\tconst char *ret = NULL; /* No default */\n");
162 } else {
163 outputf(outc,
164 "\tconst char *ret = \"%s\"; /* Default value of %s */\n",
165 defl, membere->name);
166 }
167
168 outputf(outc,
169 "\t/* ... obj@idx ... */\n"
170 "\tduk_get_prop_string(ctx, idx, \"%s\");\n"
171 "\t/* ... obj@idx ... value/undefined */\n"
172 "\tif (!duk_is_undefined(ctx, -1)) {\n"
173 "\t\t/* Note, this throws a duk_error if it's not a string */\n"
174 "\t\tret = duk_require_string(ctx, -1);\n"
175 "\t}\n"
176 "\tduk_pop(ctx);\n"
177 "\treturn ret;\n"
178 "}\n\n",
179 membere->name);
180
181 break;
182
183 case WEBIDL_TYPE_BOOL:
184 outputf(outc,
185 "duk_bool_t\n"
186 "%s_%s_get_%s(duk_context *ctx, duk_idx_t idx)\n"
187 "{\n",
188 DLPFX, dictionarye->class_name, membere->name);
189
190 if (defl == NULL) {
191 outputf(outc,
192 "\tduk_bool_t ret = false; /* No default */\n");
193 } else {
194 outputf(outc,
195 "\tduk_bool_t ret = %s; /* Default value of %s */\n",
196 defl, membere->name);
197 }
198
199 outputf(outc,
200 "\t/* ... obj@idx ... */\n"
201 "\tduk_get_prop_string(ctx, idx, \"%s\");\n"
202 "\t/* ... obj@idx ... value/undefined */\n"
203 "\tif (!duk_is_undefined(ctx, -1)) {\n"
204 "\t\t/* Note, this throws a duk_error if it's not a boolean */\n"
205 "\t\tret = duk_require_boolean(ctx, -1);\n"
206 "\t}\n"
207 "\tduk_pop(ctx);\n"
208 "\treturn ret;\n"
209 "}\n\n",
210 membere->name);
211
212 break;
213
214 case WEBIDL_TYPE_SHORT:
215 case WEBIDL_TYPE_LONG:
216 case WEBIDL_TYPE_LONGLONG:
217 outputf(outc,
218 "duk_int_t\n"
219 "%s_%s_get_%s(duk_context *ctx, duk_idx_t idx)\n"
220 "{\n",
221 DLPFX, dictionarye->class_name, membere->name);
222
223 if (defl == NULL) {
224 outputf(outc,
225 "\tduk_int_t ret = 0; /* No default */\n");
226 } else {
227 outputf(outc,
228 "\tduk_int_t ret = %s; /* Default value of %s */\n",
229 defl, membere->name);
230 }
231
232 outputf(outc,
233 "\t/* ... obj@idx ... */\n"
234 "\tduk_get_prop_string(ctx, idx, \"%s\");\n"
235 "\t/* ... obj@idx ... value/undefined */\n"
236 "\tif (!duk_is_undefined(ctx, -1)) {\n"
237 "\t\t/* Note, this throws a duk_error if it's not a int */\n"
238 "\t\tret = duk_require_int(ctx, -1);\n"
239 "\t}\n"
240 "\tduk_pop(ctx);\n"
241 "\treturn ret;\n"
242 "}\n\n",
243 membere->name);
244 break;
245
246 case WEBIDL_TYPE_FLOAT:
247 case WEBIDL_TYPE_DOUBLE:
248 outputf(outc,
249 "duk_double_t\n"
250 "%s_%s_get_%s(duk_context *ctx, duk_idx_t idx)\n",
251 DLPFX, dictionarye->class_name, membere->name);
252
253 outputf(outc,
254 "{\n"
255 "\tduk_double_t ret = %s; /* Default value of %s */\n"
256 "\t/* ... obj@idx ... */\n"
257 "\tduk_get_prop_string(ctx, idx, \"%s\");\n",
258 defl, membere->name, membere->name);
259
260 outputf(outc,
261 "\t/* ... obj@idx ... value/undefined */\n"
262 "\tif (!duk_is_undefined(ctx, -1)) {\n"
263 "\t\t/* Note, this throws a duk_error if it's not a number */\n"
264 "\t\tret = duk_require_number(ctx, -1);\n"
265 "\t}\n"
266 "\tduk_pop(ctx);\n"
267 "\treturn ret;\n"
268 "}\n\n");
269 break;
270
271 default:
272 WARN(WARNING_UNIMPLEMENTED,
273 "Dictionary %s:%s unhandled type (%d)",
274 dictionarye->name,
275 membere->name,
276 *argument_type);
277 outputf(outc,
278 "/* Dictionary %s:%s unhandled type (%d) */\n\n",
279 dictionarye->name,
280 membere->name,
281 *argument_type);
282 }
283
284 if (defl != NULL) {
285 free(defl);
286 }
287
288 return 0;
289 }
290
291 static int
output_member_acessors(struct opctx * outc,struct ir_entry * dictionarye)292 output_member_acessors(struct opctx *outc, struct ir_entry *dictionarye)
293 {
294 int memberc;
295 int res = 0;
296
297 for (memberc = 0;
298 memberc < dictionarye->u.dictionary.memberc;
299 memberc++) {
300 res = output_member_acessor(
301 outc,
302 dictionarye,
303 dictionarye->u.dictionary.memberv + memberc);
304 if (res != 0) {
305 break;
306 }
307 }
308
309 return res;
310 }
311
312
313 /* exported function documented in duk-libdom.h */
output_dictionary(struct ir * ir,struct ir_entry * dictionarye)314 int output_dictionary(struct ir *ir, struct ir_entry *dictionarye)
315 {
316 struct opctx *dyop;
317 int res = 0;
318
319 /* open the output */
320 res = output_open(dictionarye->filename, &dyop);
321 if (res != 0) {
322 return res;
323 }
324
325 /* tool preface */
326 output_tool_preface(dyop);
327
328 /* binding preface */
329 output_method_cdata(dyop,
330 ir->binding_node,
331 GENBIND_METHOD_TYPE_PREFACE);
332
333 /* class preface */
334 output_method_cdata(dyop,
335 dictionarye->class,
336 GENBIND_METHOD_TYPE_PREFACE);
337
338 /* tool prologue */
339 output_tool_prologue(dyop);
340
341 /* binding prologue */
342 output_method_cdata(dyop,
343 ir->binding_node,
344 GENBIND_METHOD_TYPE_PROLOGUE);
345
346 /* class prologue */
347 output_method_cdata(dyop,
348 dictionarye->class,
349 GENBIND_METHOD_TYPE_PROLOGUE);
350
351 outputf(dyop, "\n");
352
353 res = output_member_acessors(dyop, dictionarye);
354 if (res != 0) {
355 goto op_error;
356 }
357
358 outputf(dyop, "\n");
359
360 /* class epilogue */
361 output_method_cdata(dyop,
362 dictionarye->class,
363 GENBIND_METHOD_TYPE_EPILOGUE);
364
365 /* binding epilogue */
366 output_method_cdata(dyop,
367 ir->binding_node,
368 GENBIND_METHOD_TYPE_EPILOGUE);
369
370 /* class postface */
371 output_method_cdata(dyop,
372 dictionarye->class,
373 GENBIND_METHOD_TYPE_POSTFACE);
374
375 /* binding postface */
376 output_method_cdata(dyop,
377 ir->binding_node,
378 GENBIND_METHOD_TYPE_POSTFACE);
379
380 op_error:
381 output_close(dyop);
382
383 return res;
384 }
385
386 /**
387 * generate a single class method declaration for an interface operation
388 */
389 static int
output_member_declaration(struct opctx * outc,struct ir_entry * dictionarye,struct ir_operation_argument_entry * membere)390 output_member_declaration(struct opctx *outc,
391 struct ir_entry *dictionarye,
392 struct ir_operation_argument_entry *membere)
393 {
394 struct webidl_node *type_node;
395 enum webidl_type *argument_type;
396
397 type_node = webidl_node_find_type(
398 webidl_node_getnode(membere->node),
399 NULL,
400 WEBIDL_NODE_TYPE_TYPE);
401
402 if (type_node == NULL) {
403 fprintf(stderr, "%s:%s has no type\n",
404 dictionarye->name,
405 membere->name);
406 return -1;
407 }
408
409 argument_type = (enum webidl_type *)webidl_node_getint(
410 webidl_node_find_type(
411 webidl_node_getnode(type_node),
412 NULL,
413 WEBIDL_NODE_TYPE_TYPE_BASE));
414
415 if (argument_type == NULL) {
416 fprintf(stderr,
417 "%s:%s has no type base\n",
418 dictionarye->name,
419 membere->name);
420 return -1;
421 }
422
423
424 switch (*argument_type) {
425
426 case WEBIDL_TYPE_STRING:
427 outputf(outc,
428 "const char *%s_%s_get_%s(duk_context *ctx, duk_idx_t idx);\n",
429 DLPFX, dictionarye->class_name, membere->name);
430 break;
431
432 case WEBIDL_TYPE_BOOL:
433 outputf(outc,
434 "duk_bool_t %s_%s_get_%s(duk_context *ctx, duk_idx_t idx);\n",
435 DLPFX, dictionarye->class_name, membere->name);
436 break;
437
438 case WEBIDL_TYPE_SHORT:
439 case WEBIDL_TYPE_LONG:
440 case WEBIDL_TYPE_LONGLONG:
441 outputf(outc,
442 "duk_int_t %s_%s_get_%s(duk_context *ctx, duk_idx_t idx);\n",
443 DLPFX, dictionarye->class_name, membere->name);
444 break;
445
446 case WEBIDL_TYPE_FLOAT:
447 case WEBIDL_TYPE_DOUBLE:
448 outputf(outc,
449 "duk_double_t %s_%s_get_%s(duk_context *ctx, duk_idx_t idx);\n",
450 DLPFX, dictionarye->class_name, membere->name);
451 break;
452
453 default:
454 outputf(outc,
455 "/* Dictionary %s:%s unhandled type (%d) */\n",
456 dictionarye->name,
457 membere->name,
458 *argument_type);
459 }
460
461 return 0;
462 }
463
464 /* exported function documented in duk-libdom.h */
465 int
output_dictionary_declaration(struct opctx * outc,struct ir_entry * dictionarye)466 output_dictionary_declaration(struct opctx *outc, struct ir_entry *dictionarye)
467 {
468 int memberc;
469 int res = 0;
470
471 for (memberc = 0;
472 memberc < dictionarye->u.dictionary.memberc;
473 memberc++) {
474 res = output_member_declaration(
475 outc,
476 dictionarye,
477 dictionarye->u.dictionary.memberv + memberc);
478 if (res != 0) {
479 break;
480 }
481 }
482
483 return res;
484 }
485