1 /* AST generator for the WEB IDL parser
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 <stdbool.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <stdarg.h>
15 
16 #include "utils.h"
17 #include "webidl-ast.h"
18 #include "options.h"
19 
20 /**
21  * standard IO handle for parse trace logging.
22  */
23 static FILE *webidl_parsetracef;
24 
25 extern int webidl_debug;
26 extern int webidl__flex_debug;
27 extern void webidl_restart(FILE*);
28 extern int webidl_parse(struct webidl_node **webidl_ast);
29 
30 struct webidl_node {
31 	enum webidl_node_type type; /* the type of the node */
32 	struct webidl_node *l; /* link to the next sibling node */
33 	union {
34 		void *value;
35 		struct webidl_node *node; /* node has a list of nodes */
36 		char *text; /* node data is text */
37                 float *flt;
38 		int number; /* node data is an integer */
39 	} r;
40 };
41 
42 /* insert node(s) at beginning of a list */
43 struct webidl_node *
webidl_node_prepend(struct webidl_node * list,struct webidl_node * inst)44 webidl_node_prepend(struct webidl_node *list, struct webidl_node *inst)
45 {
46 	struct webidl_node *end = inst;
47 
48 	if (inst == NULL) {
49 		return list; /* no node to prepend - return existing list */
50 	}
51 
52 	/* find end of inserted node list */
53 	while (end->l != NULL) {
54 		end = end->l;
55 	}
56 
57 	end->l = list;
58 
59 	return inst;
60 }
61 
62 /* append node at end of a list */
63 struct webidl_node *
webidl_node_append(struct webidl_node * list,struct webidl_node * node)64 webidl_node_append(struct webidl_node *list, struct webidl_node *node)
65 {
66 	struct webidl_node *cur = list;
67 
68 	if (cur == NULL) {
69 		return node; /* no existing list so just return node */
70 	}
71 
72 	while (cur->l != NULL) {
73 		cur = cur->l;
74 	}
75 	cur->l = node;
76 
77 	return list;
78 }
79 
80 /* prepend list to a nodes list
81  *
82  * inserts a list into the beginning of a nodes r list
83  *
84  * CAUTION: if the \a node element is not a node type the node will not be added
85  */
86 struct webidl_node *
webidl_node_add(struct webidl_node * node,struct webidl_node * list)87 webidl_node_add(struct webidl_node *node, struct webidl_node *list)
88 {
89 	if (node == NULL) {
90 		return list;
91 	}
92 
93 	/* this does not use webidl_node_getnode() as it cannot
94 	 * determine between an empty node and a node which is not a
95 	 * list type
96 	 */
97 	switch (node->type) {
98 	case WEBIDL_NODE_TYPE_ROOT:
99 	case WEBIDL_NODE_TYPE_INTERFACE:
100 	case WEBIDL_NODE_TYPE_DICTIONARY:
101 	case WEBIDL_NODE_TYPE_LIST:
102 	case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE:
103 	case WEBIDL_NODE_TYPE_ATTRIBUTE:
104 	case WEBIDL_NODE_TYPE_OPERATION:
105 	case WEBIDL_NODE_TYPE_OPTIONAL:
106 	case WEBIDL_NODE_TYPE_ARGUMENT:
107 	case WEBIDL_NODE_TYPE_TYPE:
108 	case WEBIDL_NODE_TYPE_CONST:
109 		break;
110 
111 	default:
112 		/* not a node type node */
113 		return list;
114 	}
115 
116 	node->r.node =	webidl_node_prepend(node->r.node, list);
117 
118 	return node;
119 }
120 
121 
122 struct webidl_node *
123 /* exported interface documented in webidl-ast.h */
webidl_node_new(enum webidl_node_type type,struct webidl_node * l,void * r)124 webidl_node_new(enum webidl_node_type type,
125 		struct webidl_node *l,
126 		void *r)
127 {
128 	struct webidl_node *nn;
129 	nn = calloc(1, sizeof(struct webidl_node));
130 	nn->type = type;
131 	nn->l = l;
132 	nn->r.value = r;
133 	return nn;
134 }
135 
136 /* exported interface documented in webidl-ast.h */
137 struct webidl_node *
webidl_new_number_node(enum webidl_node_type type,struct webidl_node * l,int number)138 webidl_new_number_node(enum webidl_node_type type,
139                        struct webidl_node *l,
140                        int number)
141 {
142 	struct webidl_node *nn;
143 	nn = calloc(1, sizeof(struct webidl_node));
144 	nn->type = type;
145 	nn->l = l;
146 	nn->r.number = number;
147 	return nn;
148 }
149 
150 
151 int
webidl_node_for_each_type(struct webidl_node * node,enum webidl_node_type type,webidl_callback_t * cb,void * ctx)152 webidl_node_for_each_type(struct webidl_node *node,
153 			   enum webidl_node_type type,
154 			   webidl_callback_t *cb,
155 			   void *ctx)
156 {
157 	int ret;
158 
159 	if (node == NULL) {
160 		return -1;
161 	}
162 	if (node->l != NULL) {
163 		ret = webidl_node_for_each_type(node->l, type, cb, ctx);
164 		if (ret != 0) {
165 			return ret;
166 		}
167 	}
168 	if (node->type == type) {
169 		return cb(node, ctx);
170 	}
171 
172 	return 0;
173 }
174 
175 /* exported interface defined in webidl-ast.h */
webidl_cmp_node_type(struct webidl_node * node,void * ctx)176 int webidl_cmp_node_type(struct webidl_node *node, void *ctx)
177 {
178 	if (node->type == (enum webidl_node_type)ctx)
179 		return 1;
180 	return 0;
181 }
182 
webidl_enumerate_node(struct webidl_node * node,void * ctx)183 static int webidl_enumerate_node(struct webidl_node *node, void *ctx)
184 {
185 	UNUSED(node);
186 	(*((int *)ctx))++;
187 	return 0;
188 }
189 
190 /* exported interface defined in nsgenbind-ast.h */
191 int
webidl_node_enumerate_type(struct webidl_node * node,enum webidl_node_type type)192 webidl_node_enumerate_type(struct webidl_node *node,
193 			    enum webidl_node_type type)
194 {
195 	int count = 0;
196 	webidl_node_for_each_type(node,
197 				  type,
198 				  webidl_enumerate_node,
199 				  &count);
200 	return count;
201 }
202 
203 /* exported interface defined in webidl-ast.h */
204 struct webidl_node *
webidl_node_find(struct webidl_node * node,struct webidl_node * prev,webidl_callback_t * cb,void * ctx)205 webidl_node_find(struct webidl_node *node,
206 		  struct webidl_node *prev,
207 		  webidl_callback_t *cb,
208 		  void *ctx)
209 {
210 	struct webidl_node *ret;
211 
212 	if ((node == NULL) || (node == prev)) {
213 		return NULL;
214 	}
215 
216 	if (node->l != prev) {
217 		ret = webidl_node_find(node->l, prev, cb, ctx);
218 		if (ret != NULL) {
219 			return ret;
220 		}
221 	}
222 
223 	if (cb(node, ctx) != 0) {
224 		return node;
225 	}
226 
227 	return NULL;
228 }
229 
230 
231 /* exported interface defined in webidl-ast.h */
232 struct webidl_node *
webidl_node_find_type(struct webidl_node * node,struct webidl_node * prev,enum webidl_node_type type)233 webidl_node_find_type(struct webidl_node *node,
234 		  struct webidl_node *prev,
235 		  enum webidl_node_type type)
236 {
237 	return webidl_node_find(node,
238 				prev,
239 				webidl_cmp_node_type,
240 				(void *)type);
241 }
242 
243 
244 /* exported interface defined in webidl-ast.h */
245 struct webidl_node *
webidl_node_find_type_ident(struct webidl_node * root_node,enum webidl_node_type type,const char * ident)246 webidl_node_find_type_ident(struct webidl_node *root_node,
247 			    enum webidl_node_type type,
248 			    const char *ident)
249 {
250 	struct webidl_node *node;
251 	struct webidl_node *ident_node;
252 
253 	node = webidl_node_find_type(root_node,	NULL, type);
254 
255 	while (node != NULL) {
256 
257 		ident_node = webidl_node_find_type(webidl_node_getnode(node),
258 					      NULL,
259 					      WEBIDL_NODE_TYPE_IDENT);
260 		if (ident_node != NULL) {
261 			if (strcmp(ident_node->r.text, ident) == 0)
262 				break;
263 		}
264 
265 		node = webidl_node_find_type(root_node,	node, type);
266 
267 	}
268 	return node;
269 }
270 
271 
272 /* exported interface defined in webidl-ast.h */
webidl_node_gettext(struct webidl_node * node)273 char *webidl_node_gettext(struct webidl_node *node)
274 {
275 	if (node != NULL) {
276 
277 		switch(node->type) {
278 		case WEBIDL_NODE_TYPE_IDENT:
279 		case WEBIDL_NODE_TYPE_INHERITANCE:
280 		case WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS:
281                 case WEBIDL_NODE_TYPE_LITERAL_STRING:
282 			return node->r.text;
283 
284 		default:
285 			break;
286 		}
287 	}
288 	return NULL;
289 }
290 
291 /* exported interface defined in webidl-ast.h */
292 int *
webidl_node_getint(struct webidl_node * node)293 webidl_node_getint(struct webidl_node *node)
294 {
295 	if (node != NULL) {
296 		switch(node->type) {
297 		case WEBIDL_NODE_TYPE_MODIFIER:
298 		case WEBIDL_NODE_TYPE_TYPE_BASE:
299 		case WEBIDL_NODE_TYPE_LITERAL_INT:
300                 case WEBIDL_NODE_TYPE_SPECIAL:
301                 case WEBIDL_NODE_TYPE_LITERAL_BOOL:
302 			return &node->r.number;
303 
304 		default:
305 			break;
306 		}
307 	}
308 	return NULL;
309 }
310 
311 /* exported interface defined in webidl-ast.h */
312 float *
webidl_node_getfloat(struct webidl_node * node)313 webidl_node_getfloat(struct webidl_node *node)
314 {
315 	if (node != NULL) {
316 		switch(node->type) {
317                 case WEBIDL_NODE_TYPE_LITERAL_FLOAT:
318 			return node->r.flt;
319 
320 		default:
321 			break;
322 		}
323 	}
324 	return NULL;
325 }
326 
327 /* exported interface defined in webidl-ast.h */
webidl_node_gettype(struct webidl_node * node)328 enum webidl_node_type webidl_node_gettype(struct webidl_node *node)
329 {
330 	return node->type;
331 }
332 
333 
334 /* exported interface defined in webidl-ast.h */
webidl_node_getnode(struct webidl_node * node)335 struct webidl_node *webidl_node_getnode(struct webidl_node *node)
336 {
337 	if (node != NULL) {
338 		switch (node->type) {
339 		case WEBIDL_NODE_TYPE_ROOT:
340 		case WEBIDL_NODE_TYPE_INTERFACE:
341 		case WEBIDL_NODE_TYPE_DICTIONARY:
342 		case WEBIDL_NODE_TYPE_LIST:
343 		case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE:
344 		case WEBIDL_NODE_TYPE_ATTRIBUTE:
345 		case WEBIDL_NODE_TYPE_OPERATION:
346 		case WEBIDL_NODE_TYPE_OPTIONAL:
347 		case WEBIDL_NODE_TYPE_ARGUMENT:
348 		case WEBIDL_NODE_TYPE_TYPE:
349 		case WEBIDL_NODE_TYPE_CONST:
350 			return node->r.node;
351 		default:
352 			break;
353 		}
354 	}
355 	return NULL;
356 
357 }
358 
359 /* exported interface defined in webidl-ast.h */
webidl_node_type_to_str(enum webidl_node_type type)360 static const char *webidl_node_type_to_str(enum webidl_node_type type)
361 {
362 	switch(type) {
363 	case WEBIDL_NODE_TYPE_ROOT:
364 		return "root";
365 
366 	case WEBIDL_NODE_TYPE_IDENT:
367 		return "Ident";
368 
369 	case WEBIDL_NODE_TYPE_INHERITANCE:
370 		return "Inherit";
371 
372 	case WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS:
373 		return "Implements";
374 
375 	case WEBIDL_NODE_TYPE_INTERFACE:
376 		return "Interface";
377 
378 	case WEBIDL_NODE_TYPE_DICTIONARY:
379 		return "Dictionary";
380 
381 	case WEBIDL_NODE_TYPE_LIST:
382 		return "List";
383 
384 	case WEBIDL_NODE_TYPE_ATTRIBUTE:
385 		return "Attribute";
386 
387 	case WEBIDL_NODE_TYPE_OPERATION:
388 		return "Operation";
389 
390 	case WEBIDL_NODE_TYPE_OPTIONAL:
391 		return "Optional";
392 
393 	case WEBIDL_NODE_TYPE_ARGUMENT:
394 		return "Argument";
395 
396 	case WEBIDL_NODE_TYPE_ELLIPSIS:
397 		return "Ellipsis";
398 
399 	case WEBIDL_NODE_TYPE_TYPE:
400 		return "Type";
401 
402 	case WEBIDL_NODE_TYPE_TYPE_BASE:
403 		return "Base";
404 
405 	case WEBIDL_NODE_TYPE_TYPE_NULLABLE:
406 		return "Nullable";
407 
408 	case WEBIDL_NODE_TYPE_TYPE_ARRAY:
409 		return "Array";
410 
411 	case WEBIDL_NODE_TYPE_MODIFIER:
412 		return "Modifier";
413 
414 	case WEBIDL_NODE_TYPE_CONST:
415 		return "Const";
416 
417 	case WEBIDL_NODE_TYPE_LITERAL_NULL:
418 		return "Literal (null)";
419 
420 	case WEBIDL_NODE_TYPE_LITERAL_INT:
421 		return "Literal (int)";
422 
423 	case WEBIDL_NODE_TYPE_LITERAL_BOOL:
424 		return "Literal (bool)";
425 
426 	case WEBIDL_NODE_TYPE_LITERAL_FLOAT:
427 		return "Literal (float)";
428 
429 	case WEBIDL_NODE_TYPE_LITERAL_STRING:
430 		return "Literal (string)";
431 
432 	case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE:
433 		return "Extended Attribute";
434 
435 	case WEBIDL_NODE_TYPE_SPECIAL:
436 		return "Special";
437 
438 	default:
439 		return "Unknown";
440 	}
441 
442 }
443 
444 /**
445  * dump an integer node type
446  */
447 static int
webidl_ast_dump_int(FILE * dumpf,struct webidl_node * node)448 webidl_ast_dump_int(FILE *dumpf, struct webidl_node *node)
449 {
450         switch(node->type) {
451         case WEBIDL_NODE_TYPE_MODIFIER:
452                 switch (node->r.number) {
453                 case WEBIDL_TYPE_MODIFIER_NONE:
454                         fprintf(dumpf, ": none\n");
455                         break;
456 
457                 case WEBIDL_TYPE_MODIFIER_UNSIGNED:
458                         fprintf(dumpf, ": unsigned\n");
459                         break;
460 
461                 case WEBIDL_TYPE_MODIFIER_UNRESTRICTED:
462                         fprintf(dumpf, ": unrestricted\n");
463                         break;
464 
465                 case WEBIDL_TYPE_MODIFIER_READONLY:
466                         fprintf(dumpf, ": readonly\n");
467                         break;
468 
469                 case WEBIDL_TYPE_MODIFIER_STATIC:
470                         fprintf(dumpf, ": static\n");
471                         break;
472 
473                 case WEBIDL_TYPE_MODIFIER_INHERIT:
474                         fprintf(dumpf, ": inherit\n");
475                         break;
476 
477                 default:
478                         fprintf(dumpf, ": %d\n", node->r.number);
479                         break;
480                 }
481                 break;
482 
483         case WEBIDL_NODE_TYPE_TYPE_BASE:
484                 fprintf(dumpf, ": %s\n",
485                         webidl_type_to_str(WEBIDL_TYPE_MODIFIER_NONE,
486                                            node->r.number));
487                 break;
488 
489         case WEBIDL_NODE_TYPE_SPECIAL:
490                 switch (node->r.number) {
491                 case WEBIDL_TYPE_SPECIAL_GETTER:
492                         fprintf(dumpf, ": getter\n");
493                         break;
494 
495                 case WEBIDL_TYPE_SPECIAL_SETTER:
496                         fprintf(dumpf, ": setter\n");
497                         break;
498 
499                 case WEBIDL_TYPE_SPECIAL_CREATOR:
500                         fprintf(dumpf, ": creator\n");
501                         break;
502 
503                 case WEBIDL_TYPE_SPECIAL_DELETER:
504                         fprintf(dumpf, ": deleter\n");
505                         break;
506 
507                 case WEBIDL_TYPE_SPECIAL_LEGACYCALLER:
508                         fprintf(dumpf, ": legacy caller\n");
509                         break;
510 
511                 default:
512                         fprintf(dumpf, ": %d\n", node->r.number);
513                         break;
514                 }
515                 break;
516 
517         case WEBIDL_NODE_TYPE_LITERAL_BOOL:
518                 if (node->r.number == 0) {
519                         fprintf(dumpf, ": false\n");
520                 } else {
521                         fprintf(dumpf, ": true\n");
522                 }
523                 break;
524 
525         case WEBIDL_NODE_TYPE_LITERAL_INT:
526                 fprintf(dumpf, ": %d\n", node->r.number);
527                 break;
528 
529         default:
530                 /* no value */
531                 fprintf(dumpf, "\n");
532                 break;
533         }
534 
535         return 0;
536 }
537 
538 /**
539  * Recursively dump the AST nodes increasing indent as appropriate
540  */
webidl_ast_dump(FILE * dumpf,struct webidl_node * node,int indent)541 static int webidl_ast_dump(FILE *dumpf, struct webidl_node *node, int indent)
542 {
543 	const char *SPACES="                                                                               ";
544 	char *txt;
545 	while (node != NULL) {
546                 fprintf(dumpf, "%.*s%s", indent, SPACES,
547                         webidl_node_type_to_str(node->type));
548 
549 		txt = webidl_node_gettext(node);
550 		if (txt == NULL) {
551 			struct webidl_node *next;
552 
553 			next = webidl_node_getnode(node);
554 
555 			if (next != NULL) {
556 				fprintf(dumpf, "\n");
557 				webidl_ast_dump(dumpf, next, indent + 2);
558 			} else {
559 				/* not txt or node try an int */
560                                 webidl_ast_dump_int(dumpf, node);
561                         }
562 		} else {
563 			fprintf(dumpf, ": \"%s\"\n", txt);
564 		}
565 		node = node->l;
566 	}
567 	return 0;
568 }
569 
570 /* exported interface documented in webidl-ast.h */
webidl_dump_ast(struct webidl_node * node)571 int webidl_dump_ast(struct webidl_node *node)
572 {
573         FILE *dumpf;
574 
575         /* only dump AST to file if required */
576         if (!options->debug) {
577                 return 0;
578         }
579 
580         dumpf = genb_fopen("webidl-ast", "w");
581         if (dumpf == NULL) {
582                 return 2;
583         }
584 
585         webidl_ast_dump(dumpf, node, 0);
586 
587         fclose(dumpf);
588 
589         return 0;
590 }
591 
592 /* exported interface defined in webidl-ast.h */
idlopen(const char * filename)593 static FILE *idlopen(const char *filename)
594 {
595 	FILE *idlfile;
596 	char *fullname;
597 	int fulllen;
598 
599 	if (options->idlpath == NULL) {
600 		if (options->verbose) {
601 			printf("Opening IDL file %s\n", filename);
602 		}
603 		return fopen(filename, "r");
604 	}
605 
606 	fulllen = strlen(options->idlpath) + strlen(filename) + 2;
607 	fullname = malloc(fulllen);
608 	snprintf(fullname, fulllen, "%s/%s", options->idlpath, filename);
609 	if (options->verbose) {
610 		printf("Opening IDL file %s\n", fullname);
611 	}
612 	idlfile = fopen(fullname, "r");
613 	free(fullname);
614 
615 	return idlfile;
616 }
617 
618 /* exported interface defined in webidl-ast.h */
webidl_parsefile(char * filename,struct webidl_node ** webidl_ast)619 int webidl_parsefile(char *filename, struct webidl_node **webidl_ast)
620 {
621 	FILE *idlfile;
622         int ret;
623 
624 	idlfile = idlopen(filename);
625 	if (!idlfile) {
626 		fprintf(stderr, "Error opening %s: %s\n",
627 			filename,
628 			strerror(errno));
629 		return 2;
630 	}
631 
632         /* if debugging enabled enable parser tracing and send to file */
633         if (options->debug) {
634                 char *tracename;
635                 int tracenamelen;
636 		webidl_debug = 1;
637 		webidl__flex_debug = 1;
638 
639                 tracenamelen = SLEN("webidl--trace") + strlen(filename) + 1;
640                 tracename = malloc(tracenamelen);
641                 snprintf(tracename, tracenamelen,"webidl-%s-trace", filename);
642                 webidl_parsetracef = genb_fopen(tracename, "w");
643                 free(tracename);
644         } else {
645                 webidl_parsetracef = NULL;
646         }
647 
648 	/* set flex to read from file */
649 	webidl_restart(idlfile);
650 
651 	/* parse the file */
652 	ret = webidl_parse(webidl_ast);
653 
654         /* close tracefile if open */
655         if (webidl_parsetracef != NULL) {
656                 fclose(webidl_parsetracef);
657         }
658         return ret;
659 }
660 
661 /* exported interface defined in webidl-ast.h */
webidl_fprintf(FILE * stream,const char * format,...)662 int webidl_fprintf(FILE *stream, const char *format, ...)
663 {
664         va_list ap;
665         int ret;
666 
667         va_start(ap, format);
668 
669         if (webidl_parsetracef == NULL) {
670                 ret = vfprintf(stream, format, ap);
671         } else {
672                 ret = vfprintf(webidl_parsetracef, format, ap);
673         }
674         va_end(ap);
675 
676         return ret;
677 }
678 
679 /* unlink a child node from a parent */
680 static int
webidl_unlink(struct webidl_node * parent,struct webidl_node * node)681 webidl_unlink(struct webidl_node *parent, struct webidl_node *node)
682 {
683 	struct webidl_node *child;
684 
685 	child = webidl_node_getnode(parent);
686 	if (child == NULL) {
687 		/* parent does not have children to remove node from */
688 		return -1;
689 	}
690 
691 	if (child == node) {
692 		/* parent is pointing at the node we want to remove */
693 		parent->r.node = node->l; /* point parent at next sibing */
694 		node->l = NULL;
695 		return 0;
696 	}
697 
698 	while (child->l != NULL) {
699 		if (child->l == node) {
700 			/* found node, unlink from list */
701 			child->l = node->l;
702 			node->l = NULL;
703 			return 0;
704 		}
705 		child = child->l;
706 	}
707 	return -1; /* failed to remove node */
708 }
709 
implements_copy_nodes(struct webidl_node * src_node,struct webidl_node * dst_node)710 static int implements_copy_nodes(struct webidl_node *src_node,
711 				 struct webidl_node *dst_node)
712 {
713 	struct webidl_node *src;
714 	struct webidl_node *dst;
715 
716 	src = webidl_node_getnode(src_node);
717 	dst = webidl_node_getnode(dst_node);
718 
719 	while (src != NULL) {
720 		if (src->type == WEBIDL_NODE_TYPE_LIST) {
721 			/** @todo technicaly this should copy WEBIDL_NODE_TYPE_INHERITANCE */
722 			dst = webidl_node_new(src->type, dst, src->r.text);
723 		}
724 		src = src->l;
725 	}
726 
727 	dst_node->r.node = dst;
728 
729 	return 0;
730 }
731 
732 static int
intercalate_implements(struct webidl_node * interface_node,void * ctx)733 intercalate_implements(struct webidl_node *interface_node, void *ctx)
734 {
735 	struct webidl_node *implements_node;
736 	struct webidl_node *implements_interface_node;
737 	struct webidl_node *webidl_ast = ctx;
738 
739 	implements_node = webidl_node_find_type(
740 		webidl_node_getnode(interface_node),
741 		NULL,
742 		WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS);
743 	while (implements_node != NULL) {
744 
745 		implements_interface_node = webidl_node_find_type_ident(
746 			webidl_ast,
747 			WEBIDL_NODE_TYPE_INTERFACE,
748 			webidl_node_gettext(implements_node));
749 
750 		/* recurse, ensuring all subordinate interfaces have
751 		 * their implements intercalated first
752 		 */
753 		intercalate_implements(implements_interface_node, webidl_ast);
754 
755 		implements_copy_nodes(implements_interface_node, interface_node);
756 
757 		/* once we have copied the implemntation remove entry */
758 		webidl_unlink(interface_node, implements_node);
759 
760 		implements_node = webidl_node_find_type(
761 			webidl_node_getnode(interface_node),
762 			implements_node,
763 			WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS);
764 	}
765 	return 0;
766 }
767 
768 /* exported interface defined in webidl-ast.h */
webidl_intercalate_implements(struct webidl_node * webidl_ast)769 int webidl_intercalate_implements(struct webidl_node *webidl_ast)
770 {
771         int res = 0;
772         if (webidl_ast != NULL) {
773                 /* for each interface:
774                  *   for each implements entry:
775                  *     find interface from implemets
776                  *     recusrse into that interface
777                  *     copy the interface into this one
778                  */
779                 res = webidl_node_for_each_type(webidl_ast,
780                                                 WEBIDL_NODE_TYPE_INTERFACE,
781                                                 intercalate_implements,
782                                                 webidl_ast);
783         }
784         return res;
785 }
786 
787 /* exported interface defined in webidl-ast.h */
webidl_type_to_str(enum webidl_type_modifier m,enum webidl_type t)788 const char *webidl_type_to_str(enum webidl_type_modifier m, enum webidl_type t)
789 {
790         switch (t) {
791         case WEBIDL_TYPE_ANY: /**< 0 - The type is unconstrained */
792                 return "any";
793 
794         case WEBIDL_TYPE_USER: /**< 1 - The type is a dictionary or interface */
795                 return "user";
796 
797         case WEBIDL_TYPE_BOOL: /**< 2 - The type is boolean */
798                 return "boolean";
799 
800         case WEBIDL_TYPE_BYTE: /**< 3 - The type is a byte */
801                 return "byte";
802 
803         case WEBIDL_TYPE_OCTET: /**< 4 - The type is a octet */
804                 return "octet";
805 
806         case WEBIDL_TYPE_FLOAT: /**< 5 - The type is a float point number */
807                 return "float";
808 
809         case WEBIDL_TYPE_DOUBLE: /**< 6 - The type is a double */
810                 return "double";
811 
812         case WEBIDL_TYPE_SHORT: /**< 7 - The type is a signed 16bit */
813                 if (m == WEBIDL_TYPE_MODIFIER_UNSIGNED) {
814                         return "unsigned short";
815                 } else {
816                         return "short";
817                 }
818 
819         case WEBIDL_TYPE_LONG: /**< 8 - The type is a signed 32bit */
820                 if (m == WEBIDL_TYPE_MODIFIER_UNSIGNED) {
821                         return "unsigned long";
822                 } else {
823                         return "long";
824                 }
825 
826         case WEBIDL_TYPE_LONGLONG: /**< 9 - The type is a signed 64bit */
827                 return "long long";
828 
829         case WEBIDL_TYPE_STRING: /**< 10 - The type is a string */
830                 return "string";
831 
832         case WEBIDL_TYPE_SEQUENCE: /**< 11 - The type is a sequence */
833                 return "sequence";
834 
835         case WEBIDL_TYPE_OBJECT: /**< 12 - The type is a object */
836                 return "object";
837 
838         case WEBIDL_TYPE_DATE: /**< 13 - The type is a date */
839                 return "date";
840 
841         case WEBIDL_TYPE_VOID: /**< 14 - The type is void */
842                 return "void";
843         }
844         return "Unknown";
845 }
846