nsgenbind
Loading...
Searching...
No Matches
duk-libdom.c
Go to the documentation of this file.
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 2015 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
27#define DLPFX "dukky"
28
29#define MAGICPFX "\\xFF\\xFFNETSURF_DUKTAPE_"
30
44static char *get_prototype_name(const char *interface_name)
45{
46 char *proto_name;
47 int pnamelen;
48 int pfxlen;
49
50 /* duplicate the interface name in upper case */
51 pfxlen = SLEN(MAGICPFX) + SLEN("PROTOTYPE_");
52 pnamelen = strlen(interface_name) + 1;
53
54 proto_name = malloc(pnamelen + pfxlen);
55 snprintf(proto_name, pnamelen + pfxlen, "%sPROTOTYPE_%s", MAGICPFX, interface_name);
56 for (pnamelen-- ; pnamelen >= 0; pnamelen--) {
57 proto_name[pnamelen + pfxlen] = toupper(interface_name[pnamelen]);
58 }
59 return proto_name;
60}
61
62
63
64
65
66static struct opctx *open_header(struct ir *ir, const char *name)
67{
68 char *fname;
69 int fnamel;
70 struct opctx *hdrc;
71 int res;
72
73 fnamel = strlen(name) + 4;
74 fname = malloc(fnamel);
75 snprintf(fname, fnamel, "%s.h", name);
76
77 /* open the output header file */
78 res = output_open(fname, &hdrc);
79 free(fname);
80 if (res != 0 ) {
81 return NULL;
82 }
83
84 /* tool preface */
86
87 /* binding preface */
91
92 /* header guard */
93 outputf(hdrc,
94 "\n#ifndef %s_%s_h\n", DLPFX, name);
95 outputf(hdrc,
96 "#define %s_%s_h\n\n", DLPFX, name);
97
98 return hdrc;
99}
100
101static int close_header(struct ir *ir, struct opctx *hdrc)
102{
103 /* close header guard */
104 outputf(hdrc,
105 "\n#endif\n");
106
107 /* binding postface */
111
112 output_close(hdrc);
113
114 return 0;
115}
116
117
121static int
122output_private_header(struct ir *ir)
123{
124 int idx;
125 struct opctx *privc;
126
127 /* open header */
128 privc = open_header(ir, "private");
129
130 for (idx = 0; idx < ir->entryc; idx++) {
131 struct ir_entry *interfacee;
132 struct ir_entry *inherite;
133 struct genbind_node *priv_node;
134
135 interfacee = ir->entries + idx;
136
137 /* do not generate private structs for interfaces marked no
138 * output
139 */
140 if ((interfacee->type == IR_ENTRY_TYPE_INTERFACE) &&
141 (interfacee->u.interface.noobject)) {
142 continue;
143 }
144
145 switch (interfacee->type) {
147 outputf(privc,
148 "/* Private data for %s interface */\n",
149 interfacee->name);
150 break;
151
153 outputf(privc,
154 "/* Private data for %s dictionary */\n",
155 interfacee->name);
156 break;
157 }
158
159 outputf(privc,
160 "typedef struct {\n");
161
162 /* find parent entry and include in private */
163 inherite = ir_inherit_entry(ir, interfacee);
164 if (inherite != NULL) {
165 outputf(privc,
166 "\t%s_private_t parent;\n",
167 inherite->class_name);
168 }
169
170 /* for each private variable on the class output it here. */
171 priv_node = genbind_node_find_type(
172 genbind_node_getnode(interfacee->class),
173 NULL,
175 while (priv_node != NULL) {
176 outputc(privc, '\t');
177
178 output_ctype(privc, priv_node, true);
179
180 outputf(privc, ";\n");
181
182 priv_node = genbind_node_find_type(
183 genbind_node_getnode(interfacee->class),
184 priv_node,
186 }
187
188 outputf(privc,
189 "} __attribute__((aligned)) %s_private_t;\n\n",
190 interfacee->class_name);
191 }
192
193 close_header(ir, privc);
194
195 return 0;
196}
197
201static int
202output_prototype_header(struct ir *ir)
203{
204 int idx;
205 struct opctx *protoc;
206
207 /* open header */
208 protoc = open_header(ir, "prototype");
209
210 for (idx = 0; idx < ir->entryc; idx++) {
211 struct ir_entry *entry;
212
213 entry = ir->entries + idx;
214
215 switch (entry->type) {
217 output_interface_declaration(protoc, entry);
218 break;
219
221 output_dictionary_declaration(protoc, entry);
222 break;
223 }
224 }
225
226 close_header(ir, protoc);
227
228 return 0;
229}
230
234static int
235output_makefile(struct ir *ir)
236{
237 int idx;
238 FILE *makef;
239
240 /* open output file */
241 makef = genb_fopen_tmp("Makefile");
242 if (makef == NULL) {
243 return -1;
244 }
245
246 fprintf(makef, "# duk libdom makefile fragment\n\n");
247
248 fprintf(makef, "NSGENBIND_SOURCES:=binding.c ");
249 for (idx = 0; idx < ir->entryc; idx++) {
250 struct ir_entry *interfacee;
251
252 interfacee = ir->entries + idx;
253
254 /* no source for interfaces marked no output */
255 if ((interfacee->type == IR_ENTRY_TYPE_INTERFACE) &&
256 (interfacee->u.interface.noobject)) {
257 continue;
258 }
259
260 fprintf(makef, "%s ", interfacee->filename);
261 }
262 fprintf(makef, "\nNSGENBIND_PREFIX:=%s\n", options->outdirname);
263
264 genb_fclose_tmp(makef, "Makefile");
265
266 return 0;
267}
268
269
280static int
281output_binding_header(struct ir *ir)
282{
283 struct opctx *bindc;
284
285 /* open header */
286 bindc = open_header(ir, "binding");
287
288 outputf(bindc,
289 "#define _MAGIC(S) (\"%s\" S)\n"
290 "#define MAGIC(S) _MAGIC(#S)\n"
291 "#define PROTO_MAGIC MAGIC(PROTOTYPES)\n"
292 "#define PRIVATE_MAGIC MAGIC(PRIVATE)\n"
293 "#define INIT_MAGIC MAGIC(INIT)\n"
294 "#define NODE_MAGIC MAGIC(NODE_MAP)\n"
295 "#define _PROTO_NAME(K) _MAGIC(\"PROTOTYPE_\" K)\n"
296 "#define PROTO_NAME(K) _PROTO_NAME(#K)\n"
297 "#define _PROP_NAME(K,V) _MAGIC(K \"_PROPERTY_\" V)\n"
298 "#define PROP_NAME(K,V) _PROP_NAME(#K,#V)\n"
299 "\n",
300 MAGICPFX);
301
302 /* declaration of constant string values */
303 outputf(bindc,
304 "/* Constant strings */\n"
305 "extern const char *%s_error_fmt_argument;\n"
306 "extern const char *%s_error_fmt_bool_type;\n"
307 "extern const char *%s_error_fmt_number_type;\n"
308 "extern const char *%s_magic_string_private;\n"
309 "extern const char *%s_magic_string_prototypes;\n"
310 "\n",
312
313 outputf(bindc,
314 "duk_bool_t %s_instanceof(duk_context *ctx, duk_idx_t index, const char *klass);\n",
315 DLPFX);
316
317 outputf(bindc,
318 "duk_ret_t %s_create_prototypes(duk_context *ctx);\n", DLPFX);
319
320 close_header(ir, bindc);
321
322 return 0;
323}
324
325
332static int
333output_binding_src(struct ir *ir)
334{
335 int idx;
336 struct ir_entry *pglobale = NULL;
337 char *proto_name;
338 struct opctx *bindc;
339 int res;
340
341 /* open the output binding file */
342 res = output_open("binding.c", &bindc);
343 if (res != 0 ) {
344 return -1;
345 }
346
347 /* tool preface */
348 output_tool_preface(bindc);
349
350 /* binding preface */
354
355 /* tool prologue */
357
358 /* binding prologue */
362
363 outputc(bindc, '\n');
364
365 outputf(bindc,
366 "/* Error format strings */\n"
367 "const char *%s_error_fmt_argument =\"%%d argument required, but ony %%d present.\";\n"
368 "const char *%s_error_fmt_bool_type =\"argument %%d (%%s) requires a bool\";\n"
369 "const char *%s_error_fmt_number_type =\"argument %%d (%%s) requires a number\";\n",
370 DLPFX, DLPFX, DLPFX);
371
372 outputf(bindc, "\n");
373
374 outputf(bindc,
375 "/* Magic identifiers */\n"
376 "const char *%s_magic_string_private =\"%sPRIVATE\";\n"
377 "const char *%s_magic_string_prototypes =\"%sPROTOTYPES\";\n",
379
380 outputf(bindc, "\n");
381
382
383 /* instanceof helper */
384 outputf(bindc,
385 "duk_bool_t\n"
386 "%s_instanceof(duk_context *ctx, duk_idx_t _idx, const char *klass)\n"
387 "{\n"
388 "\tduk_idx_t idx = duk_normalize_index(ctx, _idx);\n"
389 "\t/* ... ??? ... */\n"
390 "\tif (!duk_check_type(ctx, idx, DUK_TYPE_OBJECT)) {\n"
391 "\t\treturn false;\n"
392 "\t}\n"
393 "\t/* ... obj ... */\n"
394 "\tduk_get_global_string(ctx, %s_magic_string_prototypes);\n"
395 "\t/* ... obj ... protos */\n"
396 "\tduk_get_prop_string(ctx, -1, klass);\n"
397 "\t/* ... obj ... protos goalproto */\n"
398 "\tduk_get_prototype(ctx, idx);\n"
399 "\t/* ... obj ... protos goalproto proto? */\n"
400 "\twhile (!duk_is_undefined(ctx, -1)) {\n"
401 "\t\tif (duk_strict_equals(ctx, -1, -2)) {\n"
402 "\t\t\tduk_pop_3(ctx);\n"
403 "\t\t\t/* ... obj ... */\n"
404 "\t\t\treturn true;\n"
405 "\t\t}\n"
406 "\t\tduk_get_prototype(ctx, -1);\n"
407 "\t\t/* ... obj ... protos goalproto proto proto? */\n"
408 "\t\tduk_replace(ctx, -2);\n"
409 "\t\t/* ... obj ... protos goalproto proto? */\n"
410 "\t}\n"
411 "\tduk_pop_3(ctx);\n"
412 "\t/* ... obj ... */\n"
413 "\treturn false;\n"
414 "}\n"
415 "\n",
416 DLPFX, DLPFX);
417
418 /* prototype creation helper function */
419 outputf(bindc,
420 "static duk_ret_t\n"
421 "%s_to_string(duk_context *ctx)\n"
422 "{\n"
423 "\t/* */\n"
424 "\tduk_push_this(ctx);\n"
425 "\t/* this */\n"
426 "\tduk_get_prototype(ctx, -1);\n"
427 "\t/* this proto */\n"
428 "\tduk_get_prop_string(ctx, -1, \"%sklass_name\");\n"
429 "\t/* this proto classname */\n"
430 "\tduk_push_string(ctx, \"[object \");\n"
431 "\t/* this proto classname str */\n"
432 "\tduk_insert(ctx, -2);\n"
433 "\t/* this proto str classname */\n"
434 "\tduk_push_string(ctx, \"]\");\n"
435 "\t/* this proto str classname str */\n"
436 "\tduk_concat(ctx, 3);\n"
437 "\t/* this proto str */\n"
438 "\treturn 1;\n"
439 "}\n"
440 "\n",
441 DLPFX,
442 MAGICPFX);
443
444 outputf(bindc,
445 "static duk_ret_t %s_create_prototype(duk_context *ctx,\n",
446 DLPFX);
447 outputf(bindc,
448 "\t\t\t\t\tduk_safe_call_function genproto,\n"
449 "\t\t\t\t\tconst char *proto_name,\n"
450 "\t\t\t\t\tconst char *klass_name)\n"
451 "{\n"
452 "\tduk_int_t ret;\n"
453 "\tduk_push_object(ctx);\n"
454 "\tif ((ret = duk_safe_call(ctx, genproto, NULL, 1, 1)) != DUK_EXEC_SUCCESS) {\n"
455 "\t\tduk_pop(ctx);\n"
456 "\t\tNSLOG(dukky, WARNING, \"Failed to register prototype for %%s\", proto_name + 2);\n"
457 "\t\treturn ret;\n"
458 "\t}\n"
459 "\t/* top of stack is the ready prototype, inject it */\n"
460 "\tduk_push_string(ctx, klass_name);\n"
461 "\tduk_put_prop_string(ctx, -2, \"%sklass_name\");\n"
462 "\tduk_push_c_function(ctx, %s_to_string, 0);\n"
463 "\tduk_put_prop_string(ctx, -2, \"toString\");\n"
464 "\tduk_push_string(ctx, \"toString\");\n"
465 "\tduk_def_prop(ctx, -2, DUK_DEFPROP_HAVE_ENUMERABLE);\n"
466 "\tduk_put_global_string(ctx, proto_name);\n"
467 "\treturn DUK_ERR_NONE;\n"
468 "}\n\n",
469 MAGICPFX,
470 DLPFX);
471
472 /* generate prototype creation */
473 outputf(bindc,
474 "duk_ret_t %s_create_prototypes(duk_context *ctx)\n", DLPFX);
475
476 outputf(bindc, "{\n");
477
478 for (idx = 0; idx < ir->entryc; idx++) {
479 struct ir_entry *interfacee;
480
481 interfacee = ir->entries + idx;
482
483 if (interfacee->type == IR_ENTRY_TYPE_DICTIONARY) {
484 continue;
485 }
486
487 /* do not generate prototype calls for interfaces marked
488 * no output
489 */
490 if (interfacee->type == IR_ENTRY_TYPE_INTERFACE) {
491 if (interfacee->u.interface.noobject) {
492 continue;
493 }
494
495 if (interfacee->u.interface.primary_global) {
496 pglobale = interfacee;
497 continue;
498 }
499 }
500 proto_name = get_prototype_name(interfacee->name);
501
502 outputf(bindc,
503 "\t%s_create_prototype(ctx, %s_%s___proto, \"%s\", \"%s\");\n",
504 DLPFX,
505 DLPFX,
506 interfacee->class_name,
507 proto_name,
508 interfacee->name);
509
510 free(proto_name);
511 }
512
513 if (pglobale != NULL) {
514 outputf(bindc, "\n\t/* Global object prototype is last */\n");
515
516 proto_name = get_prototype_name(pglobale->name);
517 outputf(bindc,
518 "\t%s_create_prototype(ctx, %s_%s___proto, \"%s\", \"%s\");\n",
519 DLPFX,
520 DLPFX,
521 pglobale->class_name,
522 proto_name,
523 pglobale->name);
524 free(proto_name);
525 }
526
527 outputf(bindc, "\n\treturn DUK_ERR_NONE;\n");
528
529 outputf(bindc, "}\n");
530
531 /* binding postface */
535
536 output_close(bindc);
537
538 return 0;
539}
540
541static int output_interfaces_dictionaries(struct ir *ir)
542{
543 int res;
544 int idx;
545
546 /* generate interfaces */
547 for (idx = 0; idx < ir->entryc; idx++) {
548 struct ir_entry *irentry;
549
550 irentry = ir->entries + idx;
551
552 switch (irentry->type) {
554 /* do not generate class for interfaces marked no
555 * output
556 */
557 if (!irentry->u.interface.noobject) {
558 res = output_interface(ir, irentry);
559 if (res != 0) {
560 return res;
561 }
562 }
563 break;
564
566 res = output_dictionary(ir, irentry);
567 if (res != 0) {
568 return res;
569 }
570
571 default:
572 break;
573 }
574 }
575
576 return 0;
577}
578
580{
581 int idx;
582 int res = 0;
583
584 /* process ir entries for output */
585 for (idx = 0; idx < ir->entryc; idx++) {
586 struct ir_entry *irentry;
587
588 irentry = ir->entries + idx;
589
590 /* compute class name */
591 irentry->class_name = gen_idl2c_name(irentry->name);
592
593 if (irentry->class_name != NULL) {
594 int ifacenamelen;
595
596 /* generate source filename */
597 ifacenamelen = strlen(irentry->class_name) + 4;
598 irentry->filename = malloc(ifacenamelen);
599 snprintf(irentry->filename,
600 ifacenamelen,
601 "%s.c",
602 irentry->class_name);
603 }
604 }
605
606 res = output_interfaces_dictionaries(ir);
607 if (res != 0) {
608 goto output_err;
609 }
610
611 /* generate private header */
612 res = output_private_header(ir);
613 if (res != 0) {
614 goto output_err;
615 }
616
617 /* generate prototype header */
618 res = output_prototype_header(ir);
619 if (res != 0) {
620 goto output_err;
621 }
622
623 /* generate binding header */
624 res = output_binding_header(ir);
625 if (res != 0) {
626 goto output_err;
627 }
628
629 /* generate binding source */
630 res = output_binding_src(ir);
631 if (res != 0) {
632 goto output_err;
633 }
634
635 /* generate makefile fragment */
636 res = output_makefile(ir);
637
638output_err:
639
640 return res;
641}
int output_method_cdata(struct opctx *outc, struct genbind_node *node, enum genbind_method_type sel_method_type)
int output_tool_prologue(struct opctx *outc)
int output_tool_preface(struct opctx *outc)
int output_ctype(struct opctx *outc, struct genbind_node *node, bool identifier)
char * gen_idl2c_name(const char *idlname)
int output_dictionary(struct ir *ir, struct ir_entry *dictionarye)
int output_dictionary_declaration(struct opctx *outc, struct ir_entry *dictionarye)
int output_interface_declaration(struct opctx *outc, struct ir_entry *interfacee)
int output_interface(struct ir *ir, struct ir_entry *interfacee)
#define DLPFX
Definition duk-libdom.c:27
int duk_libdom_output(struct ir *ir)
Definition duk-libdom.c:579
#define MAGICPFX
Definition duk-libdom.c:29
struct ir_entry * ir_inherit_entry(struct ir *map, struct ir_entry *entry)
Definition ir.c:1227
@ IR_ENTRY_TYPE_DICTIONARY
Definition ir.h:123
@ IR_ENTRY_TYPE_INTERFACE
Definition ir.h:122
struct genbind_node * genbind_node_find_type(struct genbind_node *node, struct genbind_node *prev, enum genbind_node_type type)
struct genbind_node * genbind_node_getnode(struct genbind_node *node)
@ GENBIND_METHOD_TYPE_PREFACE
@ GENBIND_METHOD_TYPE_PROLOGUE
@ GENBIND_METHOD_TYPE_POSTFACE
@ GENBIND_NODE_TYPE_PRIVATE
void * malloc(YYSIZE_T)
void free(void *)
int outputc(struct opctx *opctx, int c)
Definition output.c:88
int outputf(struct opctx *opctx, const char *fmt,...)
Definition output.c:66
int output_close(struct opctx *opctx)
Definition output.c:52
int output_open(const char *filename, struct opctx **opctx_out)
Definition output.c:23
Definition ir.h:134
char * filename
Definition ir.h:158
char * class_name
Definition ir.h:160
struct genbind_node * class
Definition ir.h:138
enum ir_entry_type type
Definition ir.h:140
const char * name
Definition ir.h:135
struct ir_interface_entry interface
Definition ir.h:143
union ir_entry::@2 u
bool noobject
Definition ir.h:95
bool primary_global
Definition ir.h:99
Definition ir.h:172
struct genbind_node * binding_node
Definition ir.h:177
int entryc
Definition ir.h:173
struct ir_entry * entries
Definition ir.h:174
Definition output.c:17
char * outdirname
Definition options.h:15
FILE * genb_fopen_tmp(const char *fname)
Definition utils.c:70
int genb_fclose_tmp(FILE *filef_tmp, const char *fname)
Definition utils.c:93
#define SLEN(s)
Definition utils.h:46