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 * generate a duktape prototype name
34 */
get_prototype_name(const char * interface_name)35 static char *get_prototype_name(const char *interface_name)
36 {
37 char *proto_name;
38 int pnamelen;
39 int pfxlen;
40
41 /* duplicate the interface name in upper case */
42 pfxlen = SLEN(MAGICPFX) + SLEN("PROTOTYPE_");
43 pnamelen = strlen(interface_name) + 1;
44
45 proto_name = malloc(pnamelen + pfxlen);
46 snprintf(proto_name, pnamelen + pfxlen,
47 "%sPROTOTYPE_%s", MAGICPFX, interface_name);
48 for (pnamelen-- ; pnamelen >= 0; pnamelen--) {
49 proto_name[pnamelen + pfxlen] = toupper(interface_name[pnamelen]);
50 }
51 return proto_name;
52 }
53
54
55 /**
56 * Compare two nodes to check their c types match.
57 */
compare_ctypes(struct genbind_node * a,struct genbind_node * b)58 static bool compare_ctypes(struct genbind_node *a, struct genbind_node *b)
59 {
60 struct genbind_node *ta;
61 struct genbind_node *tb;
62
63 ta = genbind_node_find_type(genbind_node_getnode(a),
64 NULL, GENBIND_NODE_TYPE_NAME);
65 tb = genbind_node_find_type(genbind_node_getnode(b),
66 NULL, GENBIND_NODE_TYPE_NAME);
67
68 while ((ta != NULL) && (tb != NULL)) {
69 char *txt_a;
70 char *txt_b;
71
72 txt_a = genbind_node_gettext(ta);
73 txt_b = genbind_node_gettext(tb);
74
75 if (strcmp(txt_a, txt_b) != 0) {
76 return false; /* missmatch */
77 }
78
79 ta = genbind_node_find_type(genbind_node_getnode(a),
80 ta, GENBIND_NODE_TYPE_NAME);
81 tb = genbind_node_find_type(genbind_node_getnode(b),
82 tb, GENBIND_NODE_TYPE_NAME);
83 }
84 if (ta != tb) {
85 return false;
86 }
87
88 return true;
89 }
90
91
92 /**
93 * Generate code to create a private structure
94 *
95 * \param outc Output context
96 * \param name of class private structure created for.
97 */
98 static int
output_create_private(struct opctx * outc,char * class_name)99 output_create_private(struct opctx *outc, char *class_name)
100 {
101 outputf(outc,
102 "\t/* create private data and attach to instance */\n");
103 outputf(outc,
104 "\t%s_private_t *priv = calloc(1, sizeof(*priv));\n",
105 class_name);
106 outputf(outc,
107 "\tif (priv == NULL) return 0;\n");
108 outputf(outc,
109 "\tduk_push_pointer(ctx, priv);\n");
110 outputf(outc,
111 "\tduk_put_prop_string(ctx, 0, %s_magic_string_private);\n\n",
112 DLPFX);
113
114 return 0;
115 }
116
117
118 /**
119 * generate code that gets a private pointer
120 */
121 static int
output_safe_get_private(struct opctx * outc,char * class_name,int idx)122 output_safe_get_private(struct opctx *outc, char *class_name, int idx)
123 {
124 outputf(outc,
125 "\t%s_private_t *priv;\n", class_name);
126 outputf(outc,
127 "\tduk_get_prop_string(ctx, %d, %s_magic_string_private);\n",
128 idx, DLPFX);
129 outputf(outc,
130 "\tpriv = duk_get_pointer(ctx, -1);\n");
131 outputf(outc,
132 "\tduk_pop(ctx);\n");
133 outputf(outc,
134 "\tif (priv == NULL) return 0;\n\n");
135
136 return 0;
137 }
138
139
140 /**
141 * generate code that gets a prototype by name
142 */
output_get_prototype(struct opctx * outc,const char * interface_name)143 static int output_get_prototype(struct opctx *outc, const char *interface_name)
144 {
145 char *proto_name;
146
147 proto_name = get_prototype_name(interface_name);
148
149 outputf(outc,
150 "\t/* get prototype */\n");
151 outputf(outc,
152 "\tduk_get_global_string(ctx, %s_magic_string_prototypes);\n",
153 DLPFX);
154 outputf(outc,
155 "\tduk_get_prop_string(ctx, -1, \"%s\");\n",
156 proto_name);
157 outputf(outc,
158 "\tduk_replace(ctx, -2);\n");
159
160 free(proto_name);
161
162 return 0;
163 }
164
165 /**
166 * generate code that sets a destructor in a prototype
167 */
output_set_destructor(struct opctx * outc,char * class_name,int idx)168 static int output_set_destructor(struct opctx *outc, char *class_name, int idx)
169 {
170 outputf(outc,
171 "\t/* Set the destructor */\n");
172 outputf(outc,
173 "\tduk_dup(ctx, %d);\n", idx);
174 outputf(outc,
175 "\tduk_push_c_function(ctx, %s_%s___destructor, 1);\n",
176 DLPFX, class_name);
177 outputf(outc,
178 "\tduk_set_finalizer(ctx, -2);\n");
179 outputf(outc,
180 "\tduk_pop(ctx);\n\n");
181
182 return 0;
183 }
184
185 /**
186 * generate code that sets a constructor in a prototype
187 */
188 static int
output_set_constructor(struct opctx * outc,char * class_name,int idx,int argc)189 output_set_constructor(struct opctx *outc, char *class_name, int idx, int argc)
190 {
191 outputf(outc,
192 "\t/* Set the constructor */\n");
193 outputf(outc,
194 "\tduk_dup(ctx, %d);\n", idx);
195 outputf(outc,
196 "\tduk_push_c_function(ctx, %s_%s___constructor, %d);\n",
197 DLPFX, class_name, 1 + argc);
198 outputf(outc,
199 "\tduk_put_prop_string(ctx, -2, \"%sINIT\");\n",
200 MAGICPFX);
201 outputf(outc,
202 "\tduk_pop(ctx);\n\n");
203
204 return 0;
205 }
206
207
208 /**
209 * generate code to dump javascript stack
210 */
211 static int
output_dump_stack(struct opctx * outc)212 output_dump_stack(struct opctx *outc)
213 {
214 if (options->dbglog) {
215 /* dump stack */
216 outputf(outc,
217 "\tduk_push_context_dump(ctx);\n");
218 outputf(outc,
219 "\tNSLOG(dukky, DEEPDEBUG, \"Stack: %%s\", duk_to_string(ctx, -1));\n");
220 outputf(outc,
221 "\tduk_pop(ctx);\n");
222 }
223 return 0;
224 }
225
226
227 /**
228 * generate code that adds a method in a prototype
229 */
230 static int
output_add_method(struct opctx * outc,const char * class_name,const char * method)231 output_add_method(struct opctx *outc,
232 const char *class_name,
233 const char *method)
234 {
235 outputf(outc,
236 "\t/* Add a method */\n");
237 outputf(outc,
238 "\tduk_dup(ctx, 0);\n");
239 outputf(outc,
240 "\tduk_push_string(ctx, \"%s\");\n", method);
241 outputf(outc,
242 "\tduk_push_c_function(ctx, %s_%s_%s, DUK_VARARGS);\n",
243 DLPFX, class_name, method);
244 output_dump_stack(outc);
245 outputf(outc,
246 "\tduk_def_prop(ctx, -3,\n");
247 outputf(outc,
248 "\t\t DUK_DEFPROP_HAVE_VALUE |\n");
249 outputf(outc,
250 "\t\t DUK_DEFPROP_HAVE_WRITABLE |\n");
251 outputf(outc,
252 "\t\t DUK_DEFPROP_HAVE_ENUMERABLE |\n");
253 outputf(outc,
254 "\t\t DUK_DEFPROP_ENUMERABLE |\n");
255 outputf(outc,
256 "\t\t DUK_DEFPROP_HAVE_CONFIGURABLE);\n");
257 outputf(outc,
258 "\tduk_pop(ctx);\n\n");
259
260 return 0;
261 }
262
263 /**
264 * Generate source to populate a read/write property on a prototype
265 */
266 static int
output_populate_rw_property(struct opctx * outc,const char * class_name,const char * property)267 output_populate_rw_property(struct opctx *outc,
268 const char *class_name,
269 const char *property)
270 {
271 outputf(outc,
272 "\t/* Add read/write property */\n");
273 outputf(outc,
274 "\tduk_dup(ctx, 0);\n");
275 outputf(outc,
276 "\tduk_push_string(ctx, \"%s\");\n", property);
277 outputf(outc,
278 "\tduk_push_c_function(ctx, %s_%s_%s_getter, 0);\n",
279 DLPFX, class_name, property);
280 outputf(outc,
281 "\tduk_push_c_function(ctx, %s_%s_%s_setter, 1);\n",
282 DLPFX, class_name, property);
283 output_dump_stack(outc);
284 outputf(outc,
285 "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\n");
286 outputf(outc,
287 "\t\tDUK_DEFPROP_HAVE_SETTER |\n");
288 outputf(outc,
289 "\t\tDUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |\n");
290 outputf(outc,
291 "\t\tDUK_DEFPROP_HAVE_CONFIGURABLE);\n");
292 outputf(outc,
293 "\tduk_pop(ctx);\n\n");
294
295 return 0;
296 }
297
298
299 /**
300 * Generate source to populate a readonly property on a prototype
301 */
302 static int
output_populate_ro_property(struct opctx * outc,const char * class_name,const char * property)303 output_populate_ro_property(struct opctx *outc,
304 const char *class_name,
305 const char *property)
306 {
307 outputf(outc,
308 "\t/* Add readonly property */\n");
309 outputf(outc,
310 "\tduk_dup(ctx, 0);\n");
311 outputf(outc,
312 "\tduk_push_string(ctx, \"%s\");\n", property);
313 outputf(outc,
314 "\tduk_push_c_function(ctx, %s_%s_%s_getter, 0);\n",
315 DLPFX, class_name, property);
316 output_dump_stack(outc);
317 outputf(outc,
318 "\tduk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER |\n");
319 outputf(outc,
320 "\t\tDUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |\n");
321 outputf(outc,
322 "\t\tDUK_DEFPROP_HAVE_CONFIGURABLE);\n");
323 outputf(outc,
324 "\tduk_pop(ctx);\n\n");
325
326 return 0;
327 }
328
329
330 /**
331 * Generate source to add a constant int value on a prototype
332 */
333 static int
output_prototype_constant_int(struct opctx * outc,const char * constant_name,int value)334 output_prototype_constant_int(struct opctx *outc,
335 const char *constant_name,
336 int value)
337 {
338 outputf(outc,
339 "\tduk_dup(ctx, 0);\n");
340 outputf(outc,
341 "\tduk_push_string(ctx, \"%s\");\n", constant_name);
342 outputf(outc,
343 "\tduk_push_int(ctx, %d);\n", value);
344 outputf(outc,
345 "\tduk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |\n");
346 outputf(outc,
347 "\t\t DUK_DEFPROP_HAVE_WRITABLE |\n");
348 outputf(outc,
349 "\t\t DUK_DEFPROP_HAVE_ENUMERABLE |\n");
350 outputf(outc,
351 "\t\t DUK_DEFPROP_ENUMERABLE |\n");
352 outputf(outc,
353 "\t\t DUK_DEFPROP_HAVE_CONFIGURABLE);\n");
354 outputf(outc,
355 "\tduk_pop(ctx);\n\n");
356 return 0;
357 }
358
359
360 /**
361 * generate code that gets a private pointer for a method
362 */
363 static int
output_get_method_private(struct opctx * outc,char * class_name,bool is_global)364 output_get_method_private(struct opctx *outc, char *class_name, bool is_global)
365 {
366 outputf(outc,
367 "\t/* Get private data for method */\n");
368 outputf(outc,
369 "\t%s_private_t *priv = NULL;\n", class_name);
370 if (is_global) {
371 outputf(outc,
372 "\tduk_push_global_object(ctx);\n");
373 } else {
374 outputf(outc,
375 "\tduk_push_this(ctx);\n");
376 }
377 outputf(outc,
378 "\tduk_get_prop_string(ctx, -1, %s_magic_string_private);\n",
379 DLPFX);
380 outputf(outc,
381 "\tpriv = duk_get_pointer(ctx, -1);\n");
382 outputf(outc,
383 "\tduk_pop_2(ctx);\n");
384 outputf(outc,
385 "\tif (priv == NULL) {\n");
386 if (options->dbglog) {
387 outputf(outc,
388 "\t\tNSLOG(dukky, INFO, \"priv failed\");\n");
389 }
390 outputf(outc,
391 "\t\treturn 0; /* can do? No can do. */\n");
392 outputf(outc,
393 "\t}\n\n");
394
395 return 0;
396 }
397
398
399 /**
400 * generate the interface constructor
401 */
402 static int
output_interface_constructor(struct opctx * outc,struct ir_entry * interfacee)403 output_interface_constructor(struct opctx *outc, struct ir_entry *interfacee)
404 {
405 int init_argc;
406
407 /* constructor definition */
408 outputf(outc,
409 "static duk_ret_t %s_%s___constructor(duk_context *ctx)\n",
410 DLPFX, interfacee->class_name);
411 outputf(outc,
412 "{\n");
413
414 output_create_private(outc, interfacee->class_name);
415
416 /* generate call to initialisor */
417 outputf(outc,
418 "\t%s_%s___init(ctx, priv",
419 DLPFX, interfacee->class_name);
420
421 for (init_argc = 1;
422 init_argc <= interfacee->class_init_argc;
423 init_argc++) {
424 switch (interfacee->class_init_argt[init_argc-1]) {
425 case IR_INIT_ARG_BOOL:
426 outputf(outc,
427 ", duk_get_bool(ctx, %d)",
428 init_argc);
429 break;
430 case IR_INIT_ARG_UNSIGNED:
431 case IR_INIT_ARG_INT:
432 outputf(outc,
433 ", duk_get_int(ctx, %d)",
434 init_argc);
435 break;
436 case IR_INIT_ARG_POINTER:
437 outputf(outc,
438 ", duk_get_pointer(ctx, %d)",
439 init_argc);
440 break;
441 }
442 }
443 outputf(outc,
444 ");\n");
445
446 outputf(outc,
447 "\tduk_set_top(ctx, 1);\n");
448 outputf(outc,
449 "\treturn 1;\n");
450 outputf(outc,
451 "}\n\n");
452
453 return 0;
454 }
455
456
457 /**
458 * generate the interface destructor
459 */
460 static int
output_interface_destructor(struct opctx * outc,struct ir_entry * interfacee)461 output_interface_destructor(struct opctx *outc, struct ir_entry *interfacee)
462 {
463 /* destructor definition */
464 outputf(outc,
465 "static duk_ret_t %s_%s___destructor(duk_context *ctx)\n",
466 DLPFX, interfacee->class_name);
467 outputf(outc,
468 "{\n");
469
470 output_safe_get_private(outc, interfacee->class_name, 0);
471
472 /* generate call to finaliser */
473 outputf(outc,
474 "\t%s_%s___fini(ctx, priv);\n",
475 DLPFX, interfacee->class_name);
476
477 outputf(outc,
478 "\tfree(priv);\n");
479 outputf(outc,
480 "\treturn 0;\n");
481
482 outputf(outc,
483 "}\n\n");
484
485 return 0;
486 }
487
488
489 /**
490 * generate an initialisor call to parent interface
491 */
492 static int
output_interface_inherit_init(struct opctx * outc,struct ir_entry * interfacee,struct ir_entry * inherite)493 output_interface_inherit_init(struct opctx *outc,
494 struct ir_entry *interfacee,
495 struct ir_entry *inherite)
496 {
497 struct genbind_node *init_node;
498 struct genbind_node *inh_init_node;
499 struct genbind_node *param_node;
500 struct genbind_node *inh_param_node;
501
502 /* only need to call parent initialisor if there is one */
503 if (inherite == NULL) {
504 return 0;
505 }
506
507 /* find the initialisor method on the class (if any) */
508 init_node = genbind_node_find_method(interfacee->class,
509 NULL,
510 GENBIND_METHOD_TYPE_INIT);
511
512
513 inh_init_node = genbind_node_find_method(inherite->class,
514 NULL,
515 GENBIND_METHOD_TYPE_INIT);
516
517
518 outputf(outc,
519 "\t%s_%s___init(ctx, &priv->parent",
520 DLPFX, inherite->class_name);
521
522 /* for each parameter in the parent find a matching named
523 * parameter to pass and cast if necessary
524 */
525
526 inh_param_node = genbind_node_find_type(
527 genbind_node_getnode(inh_init_node),
528 NULL, GENBIND_NODE_TYPE_PARAMETER);
529 while (inh_param_node != NULL) {
530 char *param_name;
531 param_name = genbind_node_gettext(
532 genbind_node_find_type(
533 genbind_node_getnode(inh_param_node),
534 NULL,
535 GENBIND_NODE_TYPE_IDENT));
536
537 param_node = genbind_node_find_type_ident(
538 genbind_node_getnode(init_node),
539 NULL,
540 GENBIND_NODE_TYPE_PARAMETER,
541 param_name);
542 if (param_node == NULL) {
543 fprintf(stderr,
544 "class \"%s\" (interface %s) parent class \"%s\" (interface %s) initialisor requires a parameter \"%s\" with compatible identifier\n",
545 interfacee->class_name,
546 interfacee->name,
547 inherite->class_name,
548 inherite->name,
549 param_name);
550 return -1;
551 } else {
552 outputf(outc, ", ");
553
554 /* cast the parameter if required */
555 if (compare_ctypes(param_node,
556 inh_param_node) == false) {
557 outputc(outc, '(');
558 output_ctype(outc, inh_param_node, false);
559 outputc(outc, ')');
560 }
561
562 /* output the parameter identifier */
563 output_cdata(outc, param_node, GENBIND_NODE_TYPE_IDENT);
564 }
565
566 inh_param_node = genbind_node_find_type(
567 genbind_node_getnode(inh_init_node),
568 inh_param_node, GENBIND_NODE_TYPE_METHOD);
569 }
570
571 outputf(outc, ");\n");
572
573 return 0;
574 }
575
576 static enum ir_init_argtype
guess_argtype_from(struct genbind_node * param_node)577 guess_argtype_from(struct genbind_node *param_node)
578 {
579 const char *type_cdata = NULL;
580 struct genbind_node *typename_node;
581 bool unsigned_ = false;
582 bool int_ = false;
583 bool bool_ = false;
584
585 typename_node = genbind_node_find_type(genbind_node_getnode(param_node),
586 NULL,
587 GENBIND_NODE_TYPE_NAME);
588 while (typename_node != NULL) {
589 type_cdata = genbind_node_gettext(typename_node);
590 if (strcmp(type_cdata, "unsigned") == 0) {
591 unsigned_ = true;
592 } else if (strcmp(type_cdata, "int") == 0) {
593 int_ = true;
594 } else if (strcmp(type_cdata, "bool") == 0) {
595 bool_ = true;
596 }
597 typename_node = genbind_node_find_type(
598 genbind_node_getnode(param_node),
599 typename_node,
600 GENBIND_NODE_TYPE_NAME);
601 }
602
603 if (type_cdata[0] == '*') {
604 return IR_INIT_ARG_POINTER;
605 } else if (unsigned_) {
606 return IR_INIT_ARG_UNSIGNED;
607 } else if (int_) {
608 return IR_INIT_ARG_INT;
609 } else if (bool_) {
610 return IR_INIT_ARG_BOOL;
611 }
612
613 /* If we have no better idea do this */
614 return IR_INIT_ARG_POINTER;
615 }
616
617 static int
output_interface_init_declaration(struct opctx * outc,struct ir_entry * interfacee,struct genbind_node * init_node)618 output_interface_init_declaration(struct opctx *outc,
619 struct ir_entry *interfacee,
620 struct genbind_node *init_node)
621 {
622 struct genbind_node *param_node;
623
624 if (interfacee->refcount == 0) {
625 outputf(outc, "static ");
626 }
627
628 outputf(outc,
629 "void %s_%s___init(duk_context *ctx, %s_private_t *priv",
630 DLPFX, interfacee->class_name, interfacee->class_name);
631
632 /* count the number of arguments on the initializer */
633 interfacee->class_init_argc = 0;
634 interfacee->class_init_argt = NULL;
635
636 /* output the paramters on the method (if any) */
637 param_node = genbind_node_find_type(
638 genbind_node_getnode(init_node),
639 NULL, GENBIND_NODE_TYPE_PARAMETER);
640 while (param_node != NULL) {
641 interfacee->class_init_argc++;
642 interfacee->class_init_argt = realloc(interfacee->class_init_argt,
643 interfacee->class_init_argc * sizeof(enum ir_init_argtype));
644 interfacee->class_init_argt[interfacee->class_init_argc - 1] =
645 guess_argtype_from(param_node);
646 outputf(outc, ", ");
647
648 output_ctype(outc, param_node, true);
649
650 param_node = genbind_node_find_type(
651 genbind_node_getnode(init_node),
652 param_node, GENBIND_NODE_TYPE_PARAMETER);
653 }
654
655 outputc(outc, ')');
656
657 return 0;
658 }
659
660
661 /**
662 * generate code for interface (class) initialisor
663 */
664 static int
output_interface_init(struct opctx * outc,struct ir_entry * interfacee,struct ir_entry * inherite)665 output_interface_init(struct opctx *outc,
666 struct ir_entry *interfacee,
667 struct ir_entry *inherite)
668 {
669 struct genbind_node *init_node;
670 int res;
671
672 /* find the initialisor method on the class (if any) */
673 init_node = genbind_node_find_method(interfacee->class,
674 NULL,
675 GENBIND_METHOD_TYPE_INIT);
676
677 /* initialisor definition */
678 output_interface_init_declaration(outc, interfacee, init_node);
679
680 outputf(outc, "\n{\n");
681
682 /* if this interface inherits ensure we call its initialisor */
683 res = output_interface_inherit_init(outc, interfacee, inherite);
684 if (res != 0) {
685 return res;
686 }
687
688 /* generate log statement */
689 if (options->dbglog) {
690 outputf(outc,
691 "\tNSLOG(dukky, INFO, \"Initialise %%p (priv=%%p)\", duk_get_heapptr(ctx, 0), priv);\n" );
692 }
693
694 /* output the initaliser code from the binding */
695 output_ccode(outc, init_node);
696
697 outputf(outc, "}\n\n");
698
699 return 0;
700
701 }
702
703
704 /**
705 * generate code for interface (class) finaliser
706 */
707 static int
output_interface_fini(struct opctx * outc,struct ir_entry * interfacee,struct ir_entry * inherite)708 output_interface_fini(struct opctx *outc,
709 struct ir_entry *interfacee,
710 struct ir_entry *inherite)
711 {
712 struct genbind_node *fini_node;
713
714 /* find the finaliser method on the class (if any) */
715 fini_node = genbind_node_find_method(interfacee->class,
716 NULL,
717 GENBIND_METHOD_TYPE_FINI);
718
719 /* finaliser definition */
720 if (interfacee->refcount == 0) {
721 outputf(outc, "static ");
722 }
723 outputf(outc,
724 "void %s_%s___fini(duk_context *ctx, %s_private_t *priv)\n",
725 DLPFX, interfacee->class_name, interfacee->class_name);
726 outputf(outc, "{\n");
727
728 /* generate log statement */
729 if (options->dbglog) {
730 outputf(outc,
731 "\tNSLOG(dukky, INFO, \"Finalise %%p\", duk_get_heapptr(ctx, 0));\n" );
732 }
733
734 /* output the finialisor code from the binding */
735 output_cdata(outc, fini_node, GENBIND_NODE_TYPE_CDATA);
736
737 /* if this interface inherits ensure we call its finaliser */
738 if (inherite != NULL) {
739 outputf(outc,
740 "\t%s_%s___fini(ctx, &priv->parent);\n",
741 DLPFX, inherite->class_name);
742 }
743 outputf(outc, "}\n\n");
744
745 return 0;
746 }
747
748
749 /**
750 * generate a prototype add for a single class method
751 */
752 static int
output_prototype_method(struct opctx * outc,struct ir_entry * interfacee,struct ir_operation_entry * operatione)753 output_prototype_method(struct opctx *outc,
754 struct ir_entry *interfacee,
755 struct ir_operation_entry *operatione)
756 {
757
758 if (operatione->name != NULL) {
759 /* normal method on prototype */
760 output_add_method(outc,
761 interfacee->class_name,
762 operatione->name);
763 } else {
764 /* special method on prototype */
765 outputf(outc,
766 "\t/* Special method on prototype - UNIMPLEMENTED */\n\n");
767 }
768
769 return 0;
770 }
771
772
773 /**
774 * generate prototype method definitions
775 */
776 static int
output_prototype_methods(struct opctx * outc,struct ir_entry * entry)777 output_prototype_methods(struct opctx *outc, struct ir_entry *entry)
778 {
779 int opc;
780 int res = 0;
781
782 for (opc = 0; opc < entry->u.interface.operationc; opc++) {
783 res = output_prototype_method(
784 outc,
785 entry,
786 entry->u.interface.operationv + opc);
787 if (res != 0) {
788 break;
789 }
790 }
791
792 return res;
793 }
794
795
796 static int
output_prototype_attribute(struct opctx * outc,struct ir_entry * interfacee,struct ir_attribute_entry * attributee)797 output_prototype_attribute(struct opctx *outc,
798 struct ir_entry *interfacee,
799 struct ir_attribute_entry *attributee)
800 {
801 if ((attributee->putforwards == NULL) &&
802 (attributee->modifier == WEBIDL_TYPE_MODIFIER_READONLY)) {
803 return output_populate_ro_property(outc,
804 interfacee->class_name,
805 attributee->name);
806 }
807 return output_populate_rw_property(outc,
808 interfacee->class_name,
809 attributee->name);
810 }
811
812
813 /**
814 * generate prototype attribute definitions
815 */
816 static int
output_prototype_attributes(struct opctx * outc,struct ir_entry * entry)817 output_prototype_attributes(struct opctx *outc, struct ir_entry *entry)
818 {
819 int attrc;
820 int res = 0;
821
822 for (attrc = 0; attrc < entry->u.interface.attributec; attrc++) {
823 res = output_prototype_attribute(
824 outc,
825 entry,
826 entry->u.interface.attributev + attrc);
827 if (res != 0) {
828 break;
829 }
830 }
831
832 return res;
833 }
834
835
836 /**
837 * output constants on the prototype
838 *
839 * \todo This implementation assumes the constant is a literal int and should
840 * check the type node base value.
841 */
842 static int
output_prototype_constant(struct opctx * outc,struct ir_constant_entry * constante)843 output_prototype_constant(struct opctx *outc,
844 struct ir_constant_entry *constante)
845 {
846 int *value;
847
848 value = webidl_node_getint(
849 webidl_node_find_type(
850 webidl_node_getnode(constante->node),
851 NULL,
852 WEBIDL_NODE_TYPE_LITERAL_INT));
853
854 output_prototype_constant_int(outc, constante->name, *value);
855
856 return 0;
857 }
858
859
860 /**
861 * generate prototype constant definitions
862 */
863 static int
output_prototype_constants(struct opctx * outc,struct ir_entry * entry)864 output_prototype_constants(struct opctx *outc, struct ir_entry *entry)
865 {
866 int attrc;
867 int res = 0;
868
869 for (attrc = 0; attrc < entry->u.interface.constantc; attrc++) {
870 res = output_prototype_constant(
871 outc,
872 entry->u.interface.constantv + attrc);
873 if (res != 0) {
874 break;
875 }
876 }
877
878 return res;
879 }
880
881
882 static int
output_global_create_prototype(struct opctx * outc,struct ir * ir,struct ir_entry * interfacee)883 output_global_create_prototype(struct opctx *outc,
884 struct ir *ir,
885 struct ir_entry *interfacee)
886 {
887 int idx;
888
889 outputf(outc,
890 "\t/* Create interface objects */\n");
891 for (idx = 0; idx < ir->entryc; idx++) {
892 struct ir_entry *entry;
893
894 entry = ir->entries + idx;
895
896 if (entry->type == IR_ENTRY_TYPE_INTERFACE) {
897
898 if (entry->u.interface.noobject) {
899 continue;
900 }
901
902 if (entry == interfacee) {
903 outputf(outc,
904 "\tduk_dup(ctx, 0);\n");
905 } else {
906 output_get_prototype(outc, entry->name);
907 }
908
909 outputf(outc,
910 "\tdukky_inject_not_ctr(ctx, 0, \"%s\");\n",
911 entry->name);
912 }
913 }
914 return 0;
915 }
916
917
918 /**
919 * generate the interface prototype creator
920 */
921 static int
output_interface_prototype(struct opctx * outc,struct ir * ir,struct ir_entry * interfacee,struct ir_entry * inherite)922 output_interface_prototype(struct opctx *outc,
923 struct ir *ir,
924 struct ir_entry *interfacee,
925 struct ir_entry *inherite)
926 {
927 struct genbind_node *proto_node;
928
929 /* find the prototype method on the class */
930 proto_node = genbind_node_find_method(interfacee->class,
931 NULL,
932 GENBIND_METHOD_TYPE_PROTOTYPE);
933
934 /* prototype definition */
935 outputf(outc,
936 "duk_ret_t %s_%s___proto(duk_context *ctx, void *udata)\n",
937 DLPFX, interfacee->class_name);
938 outputf(outc, "{\n");
939
940 /* Output any binding data first */
941 if (output_cdata(outc, proto_node, GENBIND_NODE_TYPE_CDATA) != 0) {
942 outputf(outc,
943 "\n");
944 }
945
946 /* generate prototype chaining if interface has a parent */
947 if (inherite != NULL) {
948 outputf(outc,
949 "\t/* Set this prototype's prototype (left-parent) */\n");
950 output_get_prototype(outc, inherite->name);
951 outputf(outc,
952 "\tduk_set_prototype(ctx, 0);\n\n");
953 }
954
955 /* generate setting of methods */
956 output_prototype_methods(outc, interfacee);
957
958 /* generate setting of attributes */
959 output_prototype_attributes(outc, interfacee);
960
961 /* generate setting of constants */
962 output_prototype_constants(outc, interfacee);
963
964 /* if this is the global object, output all interfaces which do not
965 * prevent us from doing so
966 */
967 if (interfacee->u.interface.primary_global) {
968 output_global_create_prototype(outc, ir, interfacee);
969 }
970
971 /* generate setting of destructor */
972 output_set_destructor(outc, interfacee->class_name, 0);
973
974 /* generate setting of constructor */
975 output_set_constructor(outc,
976 interfacee->class_name,
977 0,
978 interfacee->class_init_argc);
979
980 outputf(outc,
981 "\treturn 1; /* The prototype object */\n");
982
983 outputf(outc,
984 "}\n\n");
985
986 return 0;
987 }
988
989
990 /**
991 * generate a single class method for an interface operation with elipsis
992 */
993 static int
output_interface_elipsis_operation(struct opctx * outc,struct ir_entry * interfacee,struct ir_operation_entry * operatione)994 output_interface_elipsis_operation(struct opctx *outc,
995 struct ir_entry *interfacee,
996 struct ir_operation_entry *operatione)
997 {
998 int cdatac; /* cdata blocks output */
999
1000 /* overloaded method definition */
1001 outputf(outc,
1002 "static duk_ret_t %s_%s_%s(duk_context *ctx)\n",
1003 DLPFX, interfacee->class_name, operatione->name);
1004 outputf(outc,
1005 "{\n");
1006
1007 /**
1008 * \todo This is where the checking of the parameters to the
1009 * operation with elipsis should go
1010 */
1011 WARN(WARNING_UNIMPLEMENTED,
1012 "Elipsis parameters not checked: method %s::%s();",
1013 interfacee->name, operatione->name);
1014
1015 output_get_method_private(outc, interfacee->class_name,
1016 interfacee->u.interface.primary_global);
1017
1018 cdatac = output_ccode(outc, operatione->method);
1019 if (cdatac == 0) {
1020 /* no implementation so generate default */
1021 WARN(WARNING_UNIMPLEMENTED,
1022 "Unimplemented: method %s::%s();",
1023 interfacee->name, operatione->name);
1024 outputf(outc,
1025 "\treturn 0;\n");
1026 }
1027
1028 outputf(outc,
1029 "}\n\n");
1030
1031 return 0;
1032 }
1033
1034
1035 /**
1036 * generate a single class method for an interface overloaded operation
1037 */
1038 static int
output_interface_overloaded_operation(struct opctx * outc,struct ir_entry * interfacee,struct ir_operation_entry * operatione)1039 output_interface_overloaded_operation(struct opctx *outc,
1040 struct ir_entry *interfacee,
1041 struct ir_operation_entry *operatione)
1042 {
1043 int cdatac; /* cdata blocks output */
1044
1045 /* overloaded method definition */
1046 outputf(outc,
1047 "static duk_ret_t %s_%s_%s(duk_context *ctx)\n",
1048 DLPFX, interfacee->class_name, operatione->name);
1049 outputf(outc,
1050 "{\n");
1051
1052 /** \todo This is where the checking of the parameters to the
1053 * overloaded operation should go
1054 */
1055
1056 output_get_method_private(outc, interfacee->class_name,
1057 interfacee->u.interface.primary_global);
1058
1059 cdatac = output_ccode(outc,
1060 operatione->method);
1061
1062 if (cdatac == 0) {
1063 /* no implementation so generate default */
1064 WARN(WARNING_UNIMPLEMENTED,
1065 "Unimplemented: method %s::%s();",
1066 interfacee->name, operatione->name);
1067 outputf(outc,
1068 "\treturn 0;\n");
1069 }
1070
1071 outputf(outc,
1072 "}\n\n");
1073
1074 return 0;
1075 }
1076
1077
1078 /**
1079 * generate a single class method for an interface special operation
1080 */
1081 static int
output_interface_special_operation(struct opctx * outc,struct ir_entry * interfacee,struct ir_operation_entry * operatione)1082 output_interface_special_operation(struct opctx *outc,
1083 struct ir_entry *interfacee,
1084 struct ir_operation_entry *operatione)
1085 {
1086 /* special method definition */
1087 outputf(outc,
1088 "/* Special method definition - UNIMPLEMENTED */\n\n");
1089
1090 WARN(WARNING_UNIMPLEMENTED,
1091 "Special operation on interface %s (operation entry %p)",
1092 interfacee->name,
1093 operatione);
1094
1095 return 0;
1096 }
1097
1098
1099 /**
1100 * generate default values on the duk stack
1101 */
1102 static int
output_operation_optional_defaults(struct opctx * outc,struct ir_operation_argument_entry * argumentv,int argumentc)1103 output_operation_optional_defaults(
1104 struct opctx *outc,
1105 struct ir_operation_argument_entry *argumentv,
1106 int argumentc)
1107 {
1108 int argc;
1109 for (argc = 0; argc < argumentc; argc++) {
1110 struct ir_operation_argument_entry *cure;
1111 struct webidl_node *lit_node; /* literal node */
1112 enum webidl_node_type lit_type;
1113 int *lit_int;
1114 char *lit_str;
1115
1116 cure = argumentv + argc;
1117
1118 lit_node = webidl_node_getnode(
1119 webidl_node_find_type(
1120 webidl_node_getnode(cure->node),
1121 NULL,
1122 WEBIDL_NODE_TYPE_OPTIONAL));
1123
1124 if (lit_node != NULL) {
1125
1126 lit_type = webidl_node_gettype(lit_node);
1127
1128 switch (lit_type) {
1129 case WEBIDL_NODE_TYPE_LITERAL_NULL:
1130 outputf(outc,
1131 "\t\tduk_push_null(ctx);\n");
1132 break;
1133
1134 case WEBIDL_NODE_TYPE_LITERAL_INT:
1135 lit_int = webidl_node_getint(lit_node);
1136 outputf(outc,
1137 "\t\tduk_push_int(ctx, %d);\n",
1138 *lit_int);
1139 break;
1140
1141 case WEBIDL_NODE_TYPE_LITERAL_BOOL:
1142 lit_int = webidl_node_getint(lit_node);
1143 outputf(outc,
1144 "\t\tduk_push_boolean(ctx, %d);\n",
1145 *lit_int);
1146 break;
1147
1148 case WEBIDL_NODE_TYPE_LITERAL_STRING:
1149 lit_str = webidl_node_gettext(lit_node);
1150 outputf(outc,
1151 "\t\tduk_push_string(ctx, \"%s\");\n",
1152 lit_str);
1153 break;
1154
1155 case WEBIDL_NODE_TYPE_LITERAL_FLOAT:
1156 default:
1157 outputf(outc,
1158 "\t\tduk_push_undefined(ctx);\n");
1159 break;
1160 }
1161 } else {
1162 outputf(outc,
1163 "\t\tduk_push_undefined(ctx);\n");
1164 }
1165 }
1166 return 0;
1167 }
1168
1169
1170 static int
output_operation_argument_type_check(struct opctx * outc,struct ir_entry * interfacee,struct ir_operation_entry * operatione,struct ir_operation_overload_entry * overloade,int argidx)1171 output_operation_argument_type_check(
1172 struct opctx *outc,
1173 struct ir_entry *interfacee,
1174 struct ir_operation_entry *operatione,
1175 struct ir_operation_overload_entry *overloade,
1176 int argidx)
1177 {
1178 struct ir_operation_argument_entry *argumente;
1179 struct webidl_node *type_node;
1180 enum webidl_type *argument_type;
1181
1182 argumente = overloade->argumentv + argidx;
1183
1184 type_node = webidl_node_find_type(
1185 webidl_node_getnode(argumente->node),
1186 NULL,
1187 WEBIDL_NODE_TYPE_TYPE);
1188
1189 if (type_node == NULL) {
1190 fprintf(stderr, "%s:%s %dth argument %s has no type\n",
1191 interfacee->name,
1192 operatione->name,
1193 argidx,
1194 argumente->name);
1195 return -1;
1196 }
1197
1198 argument_type = (enum webidl_type *)webidl_node_getint(
1199 webidl_node_find_type(
1200 webidl_node_getnode(type_node),
1201 NULL,
1202 WEBIDL_NODE_TYPE_TYPE_BASE));
1203
1204 if (argument_type == NULL) {
1205 fprintf(stderr,
1206 "%s:%s %dth argument %s has no type base\n",
1207 interfacee->name,
1208 operatione->name,
1209 argidx,
1210 argumente->name);
1211 return -1;
1212 }
1213
1214 if (*argument_type == WEBIDL_TYPE_ANY) {
1215 /* allowing any type needs no check */
1216 return 0;
1217 }
1218
1219 outputf(outc,
1220 "\tif (%s_argc > %d) {\n", DLPFX, argidx);
1221
1222 switch (*argument_type) {
1223 case WEBIDL_TYPE_STRING:
1224 /* coerce values to string */
1225 outputf(outc,
1226 "\t\tif (!duk_is_string(ctx, %d)) {\n"
1227 "\t\t\tduk_to_string(ctx, %d);\n"
1228 "\t\t}\n", argidx, argidx);
1229 break;
1230
1231 case WEBIDL_TYPE_BOOL:
1232 outputf(outc,
1233 "\t\tif (!duk_is_boolean(ctx, %d)) {\n"
1234 "\t\t\treturn duk_error(ctx, DUK_ERR_ERROR, %s_error_fmt_bool_type, %d, \"%s\");\n"
1235 "\t\t}\n", argidx, DLPFX, argidx, argumente->name);
1236 break;
1237
1238 case WEBIDL_TYPE_FLOAT:
1239 case WEBIDL_TYPE_DOUBLE:
1240 case WEBIDL_TYPE_SHORT:
1241 case WEBIDL_TYPE_LONG:
1242 case WEBIDL_TYPE_LONGLONG:
1243 outputf(outc,
1244 "\t\tif (!duk_is_number(ctx, %d)) {\n"
1245 "\t\t\treturn duk_error(ctx, DUK_ERR_ERROR, %s_error_fmt_number_type, %d, \"%s\");\n"
1246 "\t\t}\n",
1247 argidx, DLPFX, argidx, argumente->name);
1248 break;
1249
1250
1251 default:
1252 outputf(outc,
1253 "\t\t/* unhandled type check */\n");
1254 }
1255
1256 outputf(outc,
1257 "\t}\n");
1258
1259 return 0;
1260 }
1261
1262
1263 /**
1264 * generate a single class method for an interface operation
1265 */
1266 static int
output_interface_operation(struct opctx * outc,struct ir_entry * interfacee,struct ir_operation_entry * operatione)1267 output_interface_operation(struct opctx *outc,
1268 struct ir_entry *interfacee,
1269 struct ir_operation_entry *operatione)
1270 {
1271 int cdatac; /* cdata blocks output */
1272 struct ir_operation_overload_entry *overloade;
1273 int fixedargc; /* number of non optional arguments */
1274 int argidx; /* loop counter for arguments */
1275 int optargc; /* loop counter for optional arguments */
1276
1277 if (operatione->name == NULL) {
1278 return output_interface_special_operation(outc,
1279 interfacee,
1280 operatione);
1281 }
1282
1283 if (operatione->overloadc != 1) {
1284 return output_interface_overloaded_operation(outc,
1285 interfacee,
1286 operatione);
1287 }
1288
1289 if (operatione->overloadv->elipsisc != 0) {
1290 return output_interface_elipsis_operation(outc,
1291 interfacee,
1292 operatione);
1293 }
1294
1295 /* normal method definition */
1296 overloade = operatione->overloadv;
1297
1298 outputf(outc,
1299 "static duk_ret_t %s_%s_%s(duk_context *ctx)\n",
1300 DLPFX, interfacee->class_name, operatione->name);
1301 outputf(outc,
1302 "{\n");
1303
1304 /* check arguments */
1305
1306 /* generate check for minimum number of parameters */
1307
1308 fixedargc = overloade->argumentc - overloade->optionalc;
1309
1310 outputf(outc,
1311 "\t/* ensure the parameters are present */\n"
1312 "\tduk_idx_t %s_argc = duk_get_top(ctx);\n\t", DLPFX);
1313
1314 if (fixedargc > 0) {
1315 outputf(outc,
1316 "if (%s_argc < %d) {\n",
1317 DLPFX, fixedargc);
1318 outputf(outc,
1319 "\t\t/* not enough arguments */\n");
1320 outputf(outc,
1321 "\t\treturn duk_error(ctx, DUK_RET_TYPE_ERROR, %s_error_fmt_argument, %d, %s_argc);\n",
1322 DLPFX, fixedargc, DLPFX);
1323 outputf(outc,
1324 "\t} else ");
1325 }
1326
1327 for (optargc = fixedargc;
1328 optargc < overloade->argumentc;
1329 optargc++) {
1330 outputf(outc,
1331 "if (%s_argc == %d) {\n"
1332 "\t\t/* %d optional arguments need adding */\n",
1333 DLPFX,
1334 optargc,
1335 overloade->argumentc - optargc);
1336 output_operation_optional_defaults(outc,
1337 overloade->argumentv + optargc,
1338 overloade->argumentc - optargc);
1339 outputf(outc,
1340 "\t} else ");
1341 }
1342
1343 outputf(outc,
1344 "if (%s_argc > %d) {\n"
1345 "\t\t/* remove extraneous parameters */\n"
1346 "\t\tduk_set_top(ctx, %d);\n"
1347 "\t}\n",
1348 DLPFX,
1349 overloade->argumentc,
1350 overloade->argumentc);
1351 outputf(outc,
1352 "\n");
1353
1354 /* generate argument type checks */
1355
1356 outputf(outc,
1357 "\t/* check types of passed arguments are correct */\n");
1358
1359 for (argidx = 0; argidx < overloade->argumentc; argidx++) {
1360 output_operation_argument_type_check(outc,
1361 interfacee,
1362 operatione,
1363 overloade,
1364 argidx);
1365 }
1366
1367 output_get_method_private(outc, interfacee->class_name,
1368 interfacee->u.interface.primary_global);
1369
1370 cdatac = output_ccode(outc, operatione->method);
1371 if (cdatac == 0) {
1372 /* no implementation so generate default */
1373 WARN(WARNING_UNIMPLEMENTED,
1374 "Unimplemented: method %s::%s();",
1375 interfacee->name, operatione->name);
1376
1377 if (options->dbglog) {
1378 outputf(outc,
1379 "\tNSLOG(dukky, WARNING, \"Unimplemented\");\n");
1380 }
1381
1382 outputf(outc,
1383 "\treturn 0;\n");
1384 }
1385
1386 outputf(outc,
1387 "}\n\n");
1388
1389 return 0;
1390 }
1391
1392 /**
1393 * generate class methods for each interface operation
1394 */
1395 static int
output_interface_operations(struct opctx * outc,struct ir_entry * ife)1396 output_interface_operations(struct opctx *outc, struct ir_entry *ife)
1397 {
1398 int opc;
1399 int res = 0;
1400
1401 for (opc = 0; opc < ife->u.interface.operationc; opc++) {
1402 res = output_interface_operation(
1403 outc,
1404 ife,
1405 ife->u.interface.operationv + opc);
1406 if (res != 0) {
1407 break;
1408 }
1409 }
1410
1411 return res;
1412 }
1413
1414
1415
1416 /**
1417 * Output class property getter for a single attribute
1418 */
1419 static int
output_attribute_getter(struct opctx * outc,struct ir_entry * interfacee,struct ir_attribute_entry * atributee)1420 output_attribute_getter(struct opctx *outc,
1421 struct ir_entry *interfacee,
1422 struct ir_attribute_entry *atributee)
1423 {
1424 /* getter definition */
1425 outputf(outc,
1426 "static duk_ret_t %s_%s_%s_getter(duk_context *ctx)\n",
1427 DLPFX, interfacee->class_name, atributee->name);
1428 outputf(outc,
1429 "{\n");
1430
1431 output_get_method_private(outc,
1432 interfacee->class_name,
1433 interfacee->u.interface.primary_global);
1434
1435 /* if binding available for this attribute getter process it */
1436 if (atributee->getter != NULL) {
1437 int res;
1438 res = output_ccode(outc, atributee->getter);
1439 if (res == 0) {
1440 /* no code provided for this getter so generate */
1441 res = output_generated_attribute_getter(outc,
1442 interfacee,
1443 atributee);
1444 }
1445 if (res >= 0) {
1446 outputf(outc,
1447 "}\n\n");
1448 return res;
1449 }
1450 }
1451
1452 /* no implementation so generate default and warnings if required */
1453 const char *type_str;
1454 if (atributee->typec == 0) {
1455 type_str = "";
1456 } else if (atributee->typec == 1) {
1457 type_str = webidl_type_to_str(atributee->typev[0].modifier,
1458 atributee->typev[0].base);
1459 } else {
1460 type_str = "multiple";
1461 }
1462
1463 WARN(WARNING_UNIMPLEMENTED,
1464 "Unimplemented: getter %s::%s(%s);",
1465 interfacee->name,
1466 atributee->name,
1467 type_str);
1468
1469 if (options->dbglog) {
1470 outputf(outc,
1471 "\tNSLOG(dukky, WARNING, \"Unimplemented\");\n" );
1472 }
1473
1474 outputf(outc,
1475 "\treturn 0;\n"
1476 "}\n\n");
1477
1478 return 0;
1479 }
1480
1481
1482 /**
1483 * Generate class property setter for a putforwards attribute
1484 */
1485 static int
output_putforwards_setter(struct opctx * outc,struct ir_entry * interfacee,struct ir_attribute_entry * atributee)1486 output_putforwards_setter(struct opctx *outc,
1487 struct ir_entry *interfacee,
1488 struct ir_attribute_entry *atributee)
1489 {
1490 /* generate autogenerated putforwards */
1491
1492 outputf(outc,
1493 "\tduk_ret_t get_ret;\n\n");
1494
1495 outputf(outc,
1496 "\tget_ret = %s_%s_%s_getter(ctx);\n",
1497 DLPFX, interfacee->class_name, atributee->name);
1498
1499 outputf(outc,
1500 "\tif (get_ret != 1) {\n"
1501 "\t\treturn 0;\n"
1502 "\t}\n\n"
1503 "\t/* parameter ... attribute */\n\n"
1504 "\tduk_dup(ctx, 0);\n"
1505 "\t/* ... attribute parameter */\n\n"
1506 "\t/* call the putforward */\n");
1507
1508 outputf(outc,
1509 "\tduk_put_prop_string(ctx, -2, \"%s\");\n\n",
1510 atributee->putforwards);
1511
1512 outputf(outc,
1513 "\treturn 0;\n");
1514
1515 return 0;
1516 }
1517
1518
1519 /**
1520 * Generate class property setter for a single attribute
1521 */
1522 static int
output_attribute_setter(struct opctx * outc,struct ir_entry * interfacee,struct ir_attribute_entry * atributee)1523 output_attribute_setter(struct opctx *outc,
1524 struct ir_entry *interfacee,
1525 struct ir_attribute_entry *atributee)
1526 {
1527 int res = -1;
1528
1529 /* setter definition */
1530 outputf(outc,
1531 "static duk_ret_t %s_%s_%s_setter(duk_context *ctx)\n",
1532 DLPFX, interfacee->class_name, atributee->name);
1533 outputf(outc,
1534 "{\n");
1535
1536 output_get_method_private(outc,
1537 interfacee->class_name,
1538 interfacee->u.interface.primary_global);
1539
1540 /* if binding available for this attribute getter process it */
1541 if (atributee->setter != NULL) {
1542 res = output_ccode(outc, atributee->setter);
1543 if (res == 0) {
1544 /* no code provided for this setter so generate */
1545 res = output_generated_attribute_setter(outc,
1546 interfacee,
1547 atributee);
1548 }
1549 } else if (atributee->putforwards != NULL) {
1550 res = output_putforwards_setter(outc,
1551 interfacee,
1552 atributee);
1553 }
1554
1555 /* implementation not generated from any other source */
1556 if (res < 0) {
1557 const char *type_str;
1558 if (atributee->typec == 0) {
1559 type_str = "";
1560 } else if (atributee->typec == 1) {
1561 type_str = webidl_type_to_str(
1562 atributee->typev[0].modifier,
1563 atributee->typev[0].base);
1564 } else {
1565 type_str = "multiple";
1566 }
1567 WARN(WARNING_UNIMPLEMENTED,
1568 "Unimplemented: setter %s::%s(%s);",
1569 interfacee->name,
1570 atributee->name,
1571 type_str);
1572 if (options->dbglog) {
1573 outputf(outc,
1574 "\tNSLOG(dukky, WARNING, \"Unimplemented\");\n");
1575 }
1576
1577 /* no implementation so generate default */
1578 outputf(outc,
1579 "\treturn 0;\n");
1580 }
1581
1582 outputf(outc,
1583 "}\n\n");
1584
1585 return res;
1586 }
1587
1588
1589 /**
1590 * Generate class property getter/setter for a single attribute
1591 */
1592 static int
output_interface_attribute(struct opctx * outc,struct ir_entry * interfacee,struct ir_attribute_entry * atributee)1593 output_interface_attribute(struct opctx *outc,
1594 struct ir_entry *interfacee,
1595 struct ir_attribute_entry *atributee)
1596 {
1597 int res;
1598
1599 if (atributee->property_name == NULL) {
1600 atributee->property_name = gen_idl2c_name(atributee->name);
1601 }
1602
1603 res = output_attribute_getter(outc, interfacee, atributee);
1604
1605 /* only read/write and putforward attributes have a setter */
1606 if ((atributee->modifier != WEBIDL_TYPE_MODIFIER_READONLY) ||
1607 (atributee->putforwards != NULL)) {
1608 res = output_attribute_setter(outc, interfacee, atributee);
1609 }
1610
1611 return res;
1612 }
1613
1614
1615 /**
1616 * generate class property getters and setters for each interface attribute
1617 */
1618 static int
output_interface_attributes(struct opctx * outc,struct ir_entry * ife)1619 output_interface_attributes(struct opctx *outc, struct ir_entry *ife)
1620 {
1621 int attrc;
1622
1623 for (attrc = 0; attrc < ife->u.interface.attributec; attrc++) {
1624 output_interface_attribute(
1625 outc,
1626 ife,
1627 ife->u.interface.attributev + attrc);
1628 }
1629
1630 return 0;
1631 }
1632
1633
1634 /*
1635 * generate a source file to implement an interface using duk and libdom.
1636 *
1637 * exported interface documented in duk-libdom.h
1638 */
output_interface(struct ir * ir,struct ir_entry * interfacee)1639 int output_interface(struct ir *ir, struct ir_entry *interfacee)
1640 {
1641 struct opctx *ifop;
1642 struct ir_entry *inherite;
1643 int res = 0;
1644
1645 /* open the output */
1646 res = output_open(interfacee->filename, &ifop);
1647 if (res !=0 ) {
1648 return res;
1649 }
1650
1651 /* find parent interface entry */
1652 inherite = ir_inherit_entry(ir, interfacee);
1653
1654 /* tool preface */
1655 output_tool_preface(ifop);
1656
1657 /* binding preface */
1658 output_method_cdata(ifop,
1659 ir->binding_node,
1660 GENBIND_METHOD_TYPE_PREFACE);
1661
1662 /* class preface */
1663 output_method_cdata(ifop,
1664 interfacee->class,
1665 GENBIND_METHOD_TYPE_PREFACE);
1666
1667 /* tool prologue */
1668 output_tool_prologue(ifop);
1669
1670 /* binding prologue */
1671 output_method_cdata(ifop,
1672 ir->binding_node,
1673 GENBIND_METHOD_TYPE_PROLOGUE);
1674
1675 /* class prologue */
1676 output_method_cdata(ifop,
1677 interfacee->class,
1678 GENBIND_METHOD_TYPE_PROLOGUE);
1679
1680 outputf(ifop,
1681 "\n");
1682
1683 /* initialisor */
1684 res = output_interface_init(ifop, interfacee, inherite);
1685 if (res != 0) {
1686 goto op_error;
1687 }
1688
1689 /* finaliser */
1690 output_interface_fini(ifop, interfacee, inherite);
1691
1692 /* constructor */
1693 output_interface_constructor(ifop, interfacee);
1694
1695 /* destructor */
1696 output_interface_destructor(ifop, interfacee);
1697
1698 /* operations */
1699 output_interface_operations(ifop, interfacee);
1700
1701 /* attributes */
1702 output_interface_attributes(ifop, interfacee);
1703
1704 /* prototype */
1705 output_interface_prototype(ifop, ir, interfacee, inherite);
1706
1707 outputf(ifop, "\n");
1708
1709 /* class epilogue */
1710 output_method_cdata(ifop,
1711 interfacee->class,
1712 GENBIND_METHOD_TYPE_EPILOGUE);
1713
1714 /* binding epilogue */
1715 output_method_cdata(ifop,
1716 ir->binding_node,
1717 GENBIND_METHOD_TYPE_EPILOGUE);
1718
1719 /* class postface */
1720 output_method_cdata(ifop,
1721 interfacee->class,
1722 GENBIND_METHOD_TYPE_POSTFACE);
1723
1724 /* binding postface */
1725 output_method_cdata(ifop,
1726 ir->binding_node,
1727 GENBIND_METHOD_TYPE_POSTFACE);
1728
1729 op_error:
1730 output_close(ifop);
1731
1732 return res;
1733 }
1734
1735
1736 /* exported function documented in duk-libdom.h */
1737 int
output_interface_declaration(struct opctx * outc,struct ir_entry * interfacee)1738 output_interface_declaration(struct opctx *outc, struct ir_entry *interfacee)
1739 {
1740 struct genbind_node *init_node;
1741
1742 /* do not generate prototype declarations for interfaces marked no
1743 * output
1744 */
1745 if (interfacee->u.interface.noobject) {
1746 return 0;
1747 }
1748
1749 /* prototype declaration */
1750 outputf(outc,
1751 "duk_ret_t %s_%s___proto(duk_context *ctx, void *udata);\n",
1752 DLPFX, interfacee->class_name);
1753
1754 /* if the interface has no references (no other interface inherits from
1755 * it) there is no reason to export the initalisor/finaliser as no
1756 * other class constructor/destructor should call them.
1757 */
1758 if (interfacee->refcount < 1) {
1759 outputf(outc,
1760 "\n");
1761 return 0;
1762 }
1763
1764 /* finaliser declaration */
1765 outputf(outc,
1766 "void %s_%s___fini(duk_context *ctx, %s_private_t *priv);\n",
1767 DLPFX, interfacee->class_name, interfacee->class_name);
1768
1769 /* find the initialisor method on the class (if any) */
1770 init_node = genbind_node_find_method(interfacee->class,
1771 NULL,
1772 GENBIND_METHOD_TYPE_INIT);
1773
1774 /* initialisor definition */
1775 output_interface_init_declaration(outc, interfacee, init_node);
1776
1777 outputf(outc,
1778 ";\n\n");
1779
1780 return 0;
1781 }
1782