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