VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c

Last change on this file was 103977, checked in by vboxsync, 2 months ago

Apply RT_OVERRIDE/NS_OVERRIDE where required to shut up clang.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.0 KB
Line 
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/NPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the NPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the NPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38/*
39 * Generate XPCOM headers from XPIDL.
40 */
41
42#include "xpidl.h"
43#include <ctype.h>
44
45#define AS_DECL 0
46#define AS_CALL 1
47#define AS_IMPL 2
48
49static gboolean write_method_signature(IDL_tree method_tree, FILE *outfile,
50 int mode, const char *className);
51static gboolean write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
52 gboolean getter,
53 int mode, const char *className);
54
55static void
56write_indent(FILE *outfile) {
57 fputs(" ", outfile);
58}
59
60static gboolean
61header_prolog(TreeState *state)
62{
63 char *define = xpidl_basename(state->basename);
64 fprintf(state->file, "/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM"
65 " %s.idl\n */\n", state->basename);
66 fprintf(state->file,
67 "\n#ifndef __gen_%s_h__\n"
68 "#define __gen_%s_h__\n",
69 define, define);
70 g_free(define);
71 if (state->base_includes != NULL) {
72 guint len = g_slist_length(state->base_includes);
73 guint i;
74
75 fputc('\n', state->file);
76 for (i = 0; i < len; i++) {
77 char *ident, *dot;
78
79 ident = (char *)g_slist_nth_data(state->base_includes, i);
80
81 /* suppress any trailing .extension */
82
83 /* XXX use g_basename instead ? ? */
84
85 dot = strrchr(ident, '.');
86 if (dot != NULL)
87 *dot = '\0';
88
89
90 /* begin include guard */
91 fprintf(state->file,
92 "\n#ifndef __gen_%s_h__\n",
93 ident);
94
95 fprintf(state->file, "#include \"%s.h\"\n",
96 (char *)g_slist_nth_data(state->base_includes, i));
97
98 fprintf(state->file, "#endif\n");
99
100 }
101 if (i > 0)
102 fputc('\n', state->file);
103 }
104 /*
105 * Support IDL files that don't include a root IDL file that defines
106 * NS_NO_VTABLE.
107 */
108 fprintf(state->file,
109 "/* For IDL files that don't want to include root IDL files. */\n"
110 "#ifndef NS_NO_VTABLE\n"
111 "#define NS_NO_VTABLE\n"
112 "#endif\n");
113
114 return TRUE;
115}
116
117static gboolean
118header_epilog(TreeState *state)
119{
120 char *define = xpidl_basename(state->basename);
121 fprintf(state->file, "\n#endif /* __gen_%s_h__ */\n", define);
122 g_free(define);
123 return TRUE;
124}
125
126static void
127write_classname_iid_define(FILE *file, const char *className)
128{
129 const char *iidName;
130 if (className[0] == 'n' && className[1] == 's') {
131 /* backcompat naming styles */
132 fputs("NS_", file);
133 iidName = className + 2;
134 } else {
135 iidName = className;
136 }
137 while (*iidName)
138 fputc(toupper(*iidName++), file);
139 fputs("_IID", file);
140}
141
142static gboolean
143interface(TreeState *state)
144{
145 IDL_tree iface = state->tree, iter, orig;
146 char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str;
147 char *classNameUpper = NULL;
148 char *classNameImpl = NULL;
149 char *cp;
150 gboolean ok = TRUE;
151 gboolean keepvtable;
152 const char *iid;
153 const char *name_space;
154 struct nsID id;
155 char iid_parsed[UUID_LENGTH];
156 GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments;
157
158 if (!verify_interface_declaration(iface))
159 return FALSE;
160
161#define FAIL do {ok = FALSE; goto out;} while(0)
162
163 fprintf(state->file, "\n/* starting interface: %s */\n",
164 className);
165
166 name_space = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "namespace");
167 if (name_space) {
168 fprintf(state->file, "/* namespace: %s */\n",
169 name_space);
170 fprintf(state->file, "/* fully qualified name: %s.%s */\n",
171 name_space,className);
172 }
173
174 iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid");
175 if (iid) {
176 /* Redundant, but a better error than 'cannot parse.' */
177 if (strlen(iid) != 36) {
178 IDL_tree_error(state->tree, "IID %s is the wrong length\n", iid);
179 FAIL;
180 }
181
182 /*
183 * Parse uuid and then output resulting nsID to string, to validate
184 * uuid and normalize resulting .h files.
185 */
186 if (!xpidl_parse_iid(&id, iid)) {
187 IDL_tree_error(state->tree, "cannot parse IID %s\n", iid);
188 FAIL;
189 }
190 if (!xpidl_sprint_iid(&id, iid_parsed)) {
191 IDL_tree_error(state->tree, "error formatting IID %s\n", iid);
192 FAIL;
193 }
194
195 /* #define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" */
196 fputs("#define ", state->file);
197 write_classname_iid_define(state->file, className);
198 fprintf(state->file, "_STR \"%s\"\n", iid_parsed);
199 fputc('\n', state->file);
200
201 /* #define NS_ISUPPORTS_IID { {0x00000000 .... 0x46 }} */
202 fprintf(state->file, "#define ");
203 write_classname_iid_define(state->file, className);
204 fprintf(state->file, " \\\n"
205 " {0x%.8x, 0x%.4x, 0x%.4x, \\\n"
206 " { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, "
207 "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }}\n",
208 id.m0, id.m1, id.m2,
209 id.m3[0], id.m3[1], id.m3[2], id.m3[3],
210 id.m3[4], id.m3[5], id.m3[6], id.m3[7]);
211 fputc('\n', state->file);
212 } else {
213 IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n",
214 className);
215 FAIL;
216 }
217
218 if (doc_comments != NULL)
219 printlist(state->file, doc_comments);
220
221 /*
222 * NS_NO_VTABLE is defined in nsISupportsUtils.h, and defined on windows
223 * to __declspec(novtable) on windows. This optimization is safe
224 * whenever the constructor calls no virtual methods. Writing in IDL
225 * almost guarantees this, except for the case when a %{C++ block occurs in
226 * the interface. We detect that case, and emit a macro call that disables
227 * the optimization.
228 */
229 keepvtable = FALSE;
230 for (iter = IDL_INTERFACE(state->tree).body;
231 iter != NULL;
232 iter = IDL_LIST(iter).next)
233 {
234 IDL_tree data = IDL_LIST(iter).data;
235 if (IDL_NODE_TYPE(data) == IDLN_CODEFRAG)
236 keepvtable = TRUE;
237 }
238
239 /* The interface declaration itself. */
240 fprintf(state->file,
241 "class %s%s",
242 (keepvtable ? "" : "NS_NO_VTABLE "), className);
243
244 if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
245 fputs(" : ", state->file);
246 if (IDL_LIST(iter).next != NULL) {
247 IDL_tree_error(iter,
248 "multiple inheritance is not supported by xpidl");
249 FAIL;
250 }
251 fprintf(state->file, "public %s", IDL_IDENT(IDL_LIST(iter).data).str);
252 }
253 fputs(" {\n"
254 " public: \n\n", state->file);
255 if (iid) {
256 fputs(" NS_DEFINE_STATIC_IID_ACCESSOR(", state->file);
257 write_classname_iid_define(state->file, className);
258 fputs(")\n\n", state->file);
259 }
260
261 orig = state->tree; /* It would be nice to remove this state-twiddling. */
262
263 state->tree = IDL_INTERFACE(iface).body;
264
265 if (state->tree && !xpidl_process_node(state))
266 FAIL;
267
268 fputs("};\n", state->file);
269 fputc('\n', state->file);
270
271 /*
272 * #define NS_DECL_NSIFOO - create method prototypes that can be used in
273 * class definitions that support this interface.
274 *
275 * Walk the tree explicitly to prototype a reworking of xpidl to get rid of
276 * the callback mechanism.
277 */
278 state->tree = orig;
279 fputs("/* Use this macro when declaring classes that implement this "
280 "interface. */\n", state->file);
281 fputs("#define NS_DECL_", state->file);
282 classNameUpper = xpidl_strdup(className);
283 if (!classNameUpper)
284 FAIL;
285
286 for (cp = classNameUpper; *cp != '\0'; cp++)
287 *cp = toupper(*cp);
288 fprintf(state->file, "%s \\\n", classNameUpper);
289 if (IDL_INTERFACE(state->tree).body == NULL) {
290 write_indent(state->file);
291 fputs("/* no methods! */\n", state->file);
292 }
293
294 for (iter = IDL_INTERFACE(state->tree).body;
295 iter != NULL;
296 iter = IDL_LIST(iter).next)
297 {
298 IDL_tree data = IDL_LIST(iter).data;
299
300 switch(IDL_NODE_TYPE(data)) {
301 case IDLN_OP_DCL:
302 write_indent(state->file);
303 write_method_signature(data, state->file, AS_DECL, NULL);
304 break;
305
306 case IDLN_ATTR_DCL:
307 write_indent(state->file);
308 if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
309 FAIL;
310 if (!IDL_ATTR_DCL(data).f_readonly) {
311 fputs(" NS_OVERRIDE; \\\n", state->file); /* Terminate the previous one. */
312 write_indent(state->file);
313 if (!write_attr_accessor(data, state->file,
314 FALSE, AS_DECL, NULL))
315 FAIL;
316 /* '; \n' at end will clean up. */
317 }
318 break;
319
320 case IDLN_CONST_DCL:
321 /* ignore it here; it doesn't contribute to the macro. */
322 continue;
323
324 case IDLN_CODEFRAG:
325 XPIDL_WARNING((iter, IDL_WARNING1,
326 "%%{ .. %%} code fragment within interface "
327 "ignored when generating NS_DECL_%s macro; "
328 "if the code fragment contains method "
329 "declarations, the macro probably isn't "
330 "complete.", classNameUpper));
331 continue;
332
333 default:
334 IDL_tree_error(iter,
335 "unexpected node type %d! "
336 "Please file a bug against the xpidl component.",
337 IDL_NODE_TYPE(data));
338 FAIL;
339 }
340
341 if (IDL_LIST(iter).next != NULL) {
342 fprintf(state->file, " NS_OVERRIDE; \\\n");
343 } else {
344 fprintf(state->file, " NS_OVERRIDE; \n");
345 }
346 }
347 fputc('\n', state->file);
348
349 /* XXX abstract above and below into one function? */
350 /*
351 * #define NS_FORWARD_NSIFOO - create forwarding methods that can delegate
352 * behavior from in implementation to another object. As generated by
353 * idlc.
354 */
355 fprintf(state->file,
356 "/* Use this macro to declare functions that forward the "
357 "behavior of this interface to another object. */\n"
358 "#define NS_FORWARD_%s(_to) \\\n",
359 classNameUpper);
360 if (IDL_INTERFACE(state->tree).body == NULL) {
361 write_indent(state->file);
362 fputs("/* no methods! */\n", state->file);
363 }
364
365 for (iter = IDL_INTERFACE(state->tree).body;
366 iter != NULL;
367 iter = IDL_LIST(iter).next)
368 {
369 IDL_tree data = IDL_LIST(iter).data;
370
371 switch(IDL_NODE_TYPE(data)) {
372 case IDLN_OP_DCL:
373 write_indent(state->file);
374 write_method_signature(data, state->file, AS_DECL, NULL);
375 fputs(" { return _to ", state->file);
376 write_method_signature(data, state->file, AS_CALL, NULL);
377 break;
378
379 case IDLN_ATTR_DCL:
380 write_indent(state->file);
381 if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
382 FAIL;
383 fputs(" { return _to ", state->file);
384 if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL))
385 FAIL;
386 if (!IDL_ATTR_DCL(data).f_readonly) {
387 fputs("; } \\\n", state->file); /* Terminate the previous one. */
388 write_indent(state->file);
389 if (!write_attr_accessor(data, state->file,
390 FALSE, AS_DECL, NULL))
391 FAIL;
392 fputs(" { return _to ", state->file);
393 if (!write_attr_accessor(data, state->file,
394 FALSE, AS_CALL, NULL))
395 FAIL;
396 /* '; } \n' at end will clean up. */
397 }
398 break;
399
400 case IDLN_CONST_DCL:
401 case IDLN_CODEFRAG:
402 continue;
403
404 default:
405 FAIL;
406 }
407
408 if (IDL_LIST(iter).next != NULL) {
409 fprintf(state->file, "; } \\\n");
410 } else {
411 fprintf(state->file, "; } \n");
412 }
413 }
414 fputc('\n', state->file);
415
416
417 /* XXX abstract above and below into one function? */
418 /*
419 * #define NS_FORWARD_SAFE_NSIFOO - create forwarding methods that can delegate
420 * behavior from in implementation to another object. As generated by
421 * idlc.
422 */
423 fprintf(state->file,
424 "/* Use this macro to declare functions that forward the "
425 "behavior of this interface to another object in a safe way. */\n"
426 "#define NS_FORWARD_SAFE_%s(_to) \\\n",
427 classNameUpper);
428 if (IDL_INTERFACE(state->tree).body == NULL) {
429 write_indent(state->file);
430 fputs("/* no methods! */\n", state->file);
431 }
432
433 for (iter = IDL_INTERFACE(state->tree).body;
434 iter != NULL;
435 iter = IDL_LIST(iter).next)
436 {
437 IDL_tree data = IDL_LIST(iter).data;
438
439 switch(IDL_NODE_TYPE(data)) {
440 case IDLN_OP_DCL:
441 write_indent(state->file);
442 write_method_signature(data, state->file, AS_DECL, NULL);
443 fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
444 write_method_signature(data, state->file, AS_CALL, NULL);
445 break;
446
447 case IDLN_ATTR_DCL:
448 write_indent(state->file);
449 if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
450 FAIL;
451 fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
452 if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL))
453 FAIL;
454 if (!IDL_ATTR_DCL(data).f_readonly) {
455 fputs("; } \\\n", state->file); /* Terminate the previous one. */
456 write_indent(state->file);
457 if (!write_attr_accessor(data, state->file,
458 FALSE, AS_DECL, NULL))
459 FAIL;
460 fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
461 if (!write_attr_accessor(data, state->file,
462 FALSE, AS_CALL, NULL))
463 FAIL;
464 /* '; } \n' at end will clean up. */
465 }
466 break;
467
468 case IDLN_CONST_DCL:
469 case IDLN_CODEFRAG:
470 continue;
471
472 default:
473 FAIL;
474 }
475
476 if (IDL_LIST(iter).next != NULL) {
477 fprintf(state->file, "; } \\\n");
478 } else {
479 fprintf(state->file, "; } \n");
480 }
481 }
482 fputc('\n', state->file);
483
484 /*
485 * Build a sample implementation template.
486 */
487 if (strlen(className) >= 3 && className[2] == 'I') {
488 classNameImpl = xpidl_strdup(className);
489 if (!classNameImpl)
490 FAIL;
491 memmove(&classNameImpl[2], &classNameImpl[3], strlen(classNameImpl) - 2);
492 } else {
493 classNameImpl = xpidl_strdup("_MYCLASS_");
494 if (!classNameImpl)
495 FAIL;
496 }
497
498 fputs("#if 0\n"
499 "/* Use the code below as a template for the "
500 "implementation class for this interface. */\n"
501 "\n"
502 "/* Header file */"
503 "\n",
504 state->file);
505 fprintf(state->file, "class %s : public %s\n", classNameImpl, className);
506 fputs("{\n"
507 "public:\n", state->file);
508 write_indent(state->file);
509 fputs("NS_DECL_ISUPPORTS\n", state->file);
510 write_indent(state->file);
511 fprintf(state->file, "NS_DECL_%s\n", classNameUpper);
512 fputs("\n", state->file);
513 write_indent(state->file);
514 fprintf(state->file, "%s();\n", classNameImpl);
515 fputs("\n"
516 "private:\n", state->file);
517 write_indent(state->file);
518 fprintf(state->file, "~%s();\n", classNameImpl);
519 fputs("\n"
520 "protected:\n", state->file);
521 write_indent(state->file);
522 fputs("/* additional members */\n", state->file);
523 fputs("};\n\n", state->file);
524
525 fputs("/* Implementation file */\n", state->file);
526
527 fprintf(state->file,
528 "NS_IMPL_ISUPPORTS1(%s, %s)\n", classNameImpl, className);
529 fputs("\n", state->file);
530
531 fprintf(state->file, "%s::%s()\n", classNameImpl, classNameImpl);
532 fputs("{\n", state->file);
533 write_indent(state->file);
534 fputs("/* member initializers and constructor code */\n", state->file);
535 fputs("}\n\n", state->file);
536
537 fprintf(state->file, "%s::~%s()\n", classNameImpl, classNameImpl);
538 fputs("{\n", state->file);
539 write_indent(state->file);
540 fputs("/* destructor code */\n", state->file);
541 fputs("}\n\n", state->file);
542
543 for (iter = IDL_INTERFACE(state->tree).body;
544 iter != NULL;
545 iter = IDL_LIST(iter).next)
546 {
547 IDL_tree data = IDL_LIST(iter).data;
548
549 switch(IDL_NODE_TYPE(data)) {
550 case IDLN_OP_DCL:
551 /* It would be nice to remove this state-twiddling. */
552 orig = state->tree;
553 state->tree = data;
554 xpidl_write_comment(state, 0);
555 state->tree = orig;
556
557 write_method_signature(data, state->file, AS_IMPL, classNameImpl);
558 fputs("\n{\n", state->file);
559 write_indent(state->file);
560 write_indent(state->file);
561 fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
562 "}\n"
563 "\n", state->file);
564 break;
565
566 case IDLN_ATTR_DCL:
567 /* It would be nice to remove this state-twiddling. */
568 orig = state->tree;
569 state->tree = data;
570 xpidl_write_comment(state, 0);
571 state->tree = orig;
572
573 if (!write_attr_accessor(data, state->file, TRUE,
574 AS_IMPL, classNameImpl))
575 FAIL;
576 fputs("\n{\n", state->file);
577 write_indent(state->file);
578 write_indent(state->file);
579 fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
580 "}\n", state->file);
581
582 if (!IDL_ATTR_DCL(data).f_readonly) {
583 if (!write_attr_accessor(data, state->file, FALSE,
584 AS_IMPL, classNameImpl))
585 FAIL;
586 fputs("\n{\n", state->file);
587 write_indent(state->file);
588 write_indent(state->file);
589 fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
590 "}\n", state->file);
591 }
592 fputs("\n", state->file);
593 break;
594
595 case IDLN_CONST_DCL:
596 case IDLN_CODEFRAG:
597 continue;
598
599 default:
600 FAIL;
601 }
602 }
603
604 fputs("/* End of implementation class template. */\n"
605 "#endif\n"
606 "\n", state->file);
607
608#undef FAIL
609
610out:
611 if (classNameUpper)
612 free(classNameUpper);
613 if (classNameImpl)
614 free(classNameImpl);
615 return ok;
616}
617
618static gboolean
619list(TreeState *state)
620{
621 IDL_tree iter;
622 for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
623 state->tree = IDL_LIST(iter).data;
624 if (!xpidl_process_node(state))
625 return FALSE;
626 }
627 return TRUE;
628}
629
630static gboolean
631write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile)
632{
633 if (!type_tree) {
634 fputs("void", outfile);
635 return TRUE;
636 }
637
638 switch (IDL_NODE_TYPE(type_tree)) {
639 case IDLN_TYPE_INTEGER: {
640 gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed;
641 switch (IDL_TYPE_INTEGER(type_tree).f_type) {
642 case IDL_INTEGER_TYPE_SHORT:
643 fputs(sign ? "PRInt16" : "PRUint16", outfile);
644 break;
645 case IDL_INTEGER_TYPE_LONG:
646 fputs(sign ? "PRInt32" : "PRUint32", outfile);
647 break;
648 case IDL_INTEGER_TYPE_LONGLONG:
649 fputs(sign ? "PRInt64" : "PRUint64", outfile);
650 break;
651 default:
652 g_error("Unknown integer type %d\n",
653 IDL_TYPE_INTEGER(type_tree).f_type);
654 return FALSE;
655 }
656 break;
657 }
658 case IDLN_TYPE_CHAR:
659 fputs("char", outfile);
660 break;
661 case IDLN_TYPE_WIDE_CHAR:
662 fputs("PRUnichar", outfile); /* wchar_t? */
663 break;
664 case IDLN_TYPE_WIDE_STRING:
665 fputs("PRUnichar *", outfile);
666 break;
667 case IDLN_TYPE_STRING:
668 fputs("char *", outfile);
669 break;
670 case IDLN_TYPE_BOOLEAN:
671 fputs("PRBool", outfile);
672 break;
673 case IDLN_TYPE_OCTET:
674 fputs("PRUint8", outfile);
675 break;
676 case IDLN_TYPE_FLOAT:
677 switch (IDL_TYPE_FLOAT(type_tree).f_type) {
678 case IDL_FLOAT_TYPE_FLOAT:
679 fputs("float", outfile);
680 break;
681 case IDL_FLOAT_TYPE_DOUBLE:
682 fputs("double", outfile);
683 break;
684 /* XXX 'long double' just ignored, or what? */
685 default:
686 fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
687 break;
688 }
689 break;
690 case IDLN_IDENT:
691 if (UP_IS_NATIVE(type_tree)) {
692 if (IDL_tree_property_get(type_tree, "domstring") ||
693 IDL_tree_property_get(type_tree, "astring")) {
694 fputs("nsAString", outfile);
695 } else if (IDL_tree_property_get(type_tree, "utf8string")) {
696 fputs("nsACString", outfile);
697 } else if (IDL_tree_property_get(type_tree, "cstring")) {
698 fputs("nsACString", outfile);
699 } else {
700 fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile);
701 }
702 if (IDL_tree_property_get(type_tree, "ptr")) {
703 fputs(" *", outfile);
704 } else if (IDL_tree_property_get(type_tree, "ref")) {
705 fputs(" &", outfile);
706 }
707 } else {
708 fputs(IDL_IDENT(type_tree).str, outfile);
709 }
710 if (UP_IS_AGGREGATE(type_tree))
711 fputs(" *", outfile);
712 break;
713 default:
714 fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
715 break;
716 }
717 return TRUE;
718}
719
720/*
721 * An attribute declaration looks like:
722 *
723 * [ IDL_ATTR_DCL]
724 * - param_type_spec [IDL_TYPE_* or NULL for void]
725 * - simple_declarations [IDL_LIST]
726 * - data [IDL_IDENT]
727 * - next [IDL_LIST or NULL if no more idents]
728 * - data [IDL_IDENT]
729 */
730
731#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data))
732#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec)
733#define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree)))
734
735/*
736 * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)'
737 * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)'
738 * AS_CALL writes 'foo(bar, sil)'
739 */
740static gboolean
741write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
742 gboolean getter, int mode, const char *className)
743{
744 char *attrname = ATTR_IDENT(attr_tree).str;
745
746 if (mode == AS_DECL) {
747 fputs("NS_IMETHOD ", outfile);
748 } else if (mode == AS_IMPL) {
749 fprintf(outfile, "NS_IMETHODIMP %s::", className);
750 }
751 fprintf(outfile, "%cet%c%s(",
752 getter ? 'G' : 'S',
753 toupper(*attrname), attrname + 1);
754 if (mode == AS_DECL || mode == AS_IMPL) {
755 /* Setters for string, wstring, nsid, domstring, utf8string,
756 * cstring and astring get const.
757 */
758 if (!getter &&
759 (IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_STRING ||
760 IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_WIDE_STRING ||
761 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "nsid") ||
762 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring") ||
763 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "utf8string") ||
764 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "cstring") ||
765 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "astring")))
766 {
767 fputs("const ", outfile);
768 }
769
770 if (!write_type(ATTR_TYPE_DECL(attr_tree), getter, outfile))
771 return FALSE;
772 fprintf(outfile, "%s%s",
773 (STARRED_TYPE(attr_tree) ? "" : " "),
774 (getter && !DIPPER_TYPE(ATTR_TYPE_DECL(attr_tree)))? "*" : "");
775 }
776 fprintf(outfile, "a%c%s)", toupper(attrname[0]), attrname + 1);
777 return TRUE;
778}
779
780static gboolean
781attr_dcl(TreeState *state)
782{
783 GSList *doc_comments;
784
785 if (!verify_attribute_declaration(state->tree))
786 return FALSE;
787
788 doc_comments =
789 IDL_IDENT(IDL_LIST(IDL_ATTR_DCL
790 (state->tree).simple_declarations).data).comments;
791
792 if (doc_comments != NULL) {
793 write_indent(state->file);
794 printlist(state->file, doc_comments);
795 }
796
797 /*
798 * XXX lists of attributes with the same type, e.g.
799 * attribute string foo, bar sil;
800 * are legal IDL... but we don't do anything with 'em.
801 */
802 if (IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).next != NULL) {
803 XPIDL_WARNING((state->tree, IDL_WARNING1,
804 "multiple attributes in a single declaration aren't "
805 "currently supported by xpidl"));
806 }
807
808 xpidl_write_comment(state, 2);
809
810 write_indent(state->file);
811 if (!write_attr_accessor(state->tree, state->file, TRUE, AS_DECL, NULL))
812 return FALSE;
813 fputs(" = 0;\n", state->file);
814
815 if (!IDL_ATTR_DCL(state->tree).f_readonly) {
816 write_indent(state->file);
817 if (!write_attr_accessor(state->tree, state->file, FALSE, AS_DECL, NULL))
818 return FALSE;
819 fputs(" = 0;\n", state->file);
820 }
821 fputc('\n', state->file);
822
823 return TRUE;
824}
825
826static gboolean
827do_enum(TreeState *state)
828{
829 IDL_tree_error(state->tree, "enums not supported, "
830 "see http://bugzilla.mozilla.org/show_bug.cgi?id=8781");
831 return FALSE;
832}
833
834static gboolean
835do_const_dcl(TreeState *state)
836{
837 struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree);
838 const char *name = IDL_IDENT(dcl->ident).str;
839 gboolean is_signed;
840 GSList *doc_comments = IDL_IDENT(dcl->ident).comments;
841 IDL_tree real_type;
842 const char *const_format;
843
844 if (!verify_const_declaration(state->tree))
845 return FALSE;
846
847 if (doc_comments != NULL) {
848 write_indent(state->file);
849 printlist(state->file, doc_comments);
850 }
851
852 /* Could be a typedef; try to map it to the real type. */
853 real_type = find_underlying_type(dcl->const_type);
854 real_type = real_type ? real_type : dcl->const_type;
855 is_signed = IDL_TYPE_INTEGER(real_type).f_signed;
856
857 const_format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "uU";
858 write_indent(state->file);
859 fprintf(state->file, "enum { %s = ", name);
860 fprintf(state->file, const_format, IDL_INTEGER(dcl->const_exp).value);
861 fprintf(state->file, " };\n\n");
862
863 return TRUE;
864}
865
866static gboolean
867do_typedef(TreeState *state)
868{
869 IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec;
870 IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls;
871 IDL_tree complex;
872 GSList *doc_comments;
873
874 if (IDL_NODE_TYPE(type) == IDLN_TYPE_SEQUENCE) {
875 XPIDL_WARNING((state->tree, IDL_WARNING1,
876 "sequences not supported, ignored"));
877 } else {
878 if (IDL_NODE_TYPE(complex = IDL_LIST(dcls).data) == IDLN_TYPE_ARRAY) {
879 IDL_tree dim = IDL_TYPE_ARRAY(complex).size_list;
880 doc_comments = IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).comments;
881
882 if (doc_comments != NULL)
883 printlist(state->file, doc_comments);
884
885 fputs("typedef ", state->file);
886 if (!write_type(type, FALSE, state->file))
887 return FALSE;
888 fputs(" ", state->file);
889
890 fprintf(state->file, "%s",
891 IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).str);
892 do {
893 fputc('[', state->file);
894 if (IDL_LIST(dim).data) {
895 fprintf(state->file, "%ld",
896 (long)IDL_INTEGER(IDL_LIST(dim).data).value);
897 }
898 fputc(']', state->file);
899 } while ((dim = IDL_LIST(dim).next) != NULL);
900 } else {
901 doc_comments = IDL_IDENT(IDL_LIST(dcls).data).comments;
902
903 if (doc_comments != NULL)
904 printlist(state->file, doc_comments);
905
906 fputs("typedef ", state->file);
907 if (!write_type(type, FALSE, state->file))
908 return FALSE;
909 fputs(" ", state->file);
910 fputs(IDL_IDENT(IDL_LIST(dcls).data).str, state->file);
911 }
912 fputs(";\n\n", state->file);
913 }
914 return TRUE;
915}
916
917/*
918 * param generation:
919 * in string foo --> nsString *foo
920 * out string foo --> nsString **foo;
921 * inout string foo --> nsString **foo;
922 */
923
924/* If notype is true, just write the param name. */
925static gboolean
926write_param(IDL_tree param_tree, FILE *outfile)
927{
928 IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec;
929 gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN;
930 /* in string, wstring, nsid, domstring, utf8string, cstring and
931 * astring any explicitly marked [const] are const
932 */
933
934 if (is_in &&
935 (IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_STRING ||
936 IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_WIDE_STRING ||
937 IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
938 "const") ||
939 IDL_tree_property_get(param_type_spec, "nsid") ||
940 IDL_tree_property_get(param_type_spec, "domstring") ||
941 IDL_tree_property_get(param_type_spec, "utf8string") ||
942 IDL_tree_property_get(param_type_spec, "cstring") ||
943 IDL_tree_property_get(param_type_spec, "astring"))) {
944 fputs("const ", outfile);
945 }
946 else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT &&
947 IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
948 "shared")) {
949 fputs("const ", outfile);
950 }
951
952 if (!write_type(param_type_spec, !is_in, outfile))
953 return FALSE;
954
955 /* unless the type ended in a *, add a space */
956 if (!STARRED_TYPE(param_type_spec))
957 fputc(' ', outfile);
958
959 /* out and inout params get a bonus '*' (unless this is type that has a
960 * 'dipper' class that is passed in to receive 'out' data)
961 */
962 if (IDL_PARAM_DCL(param_tree).attr != IDL_PARAM_IN &&
963 !DIPPER_TYPE(param_type_spec)) {
964 fputc('*', outfile);
965 }
966 /* arrays get a bonus * too */
967 /* XXX Should this be a leading '*' or a trailing "[]" ?*/
968 if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
969 "array"))
970 fputc('*', outfile);
971
972 fputs(IDL_IDENT(IDL_PARAM_DCL(param_tree).simple_declarator).str, outfile);
973
974 return TRUE;
975}
976
977/*
978 * A forward declaration, usually an interface.
979 */
980static gboolean
981forward_dcl(TreeState *state)
982{
983 IDL_tree iface = state->tree;
984 const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str;
985
986 if (!className)
987 return FALSE;
988
989 fprintf(state->file, "class %s; /* forward declaration */\n\n", className);
990 return TRUE;
991}
992
993/*
994 * Shared between the interface class declaration and the NS_DECL_IFOO macro
995 * provided to aid declaration of implementation classes.
996 * mode...
997 * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)'
998 * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)'
999 * AS_CALL writes 'foo(bar, sil)'
1000 */
1001static gboolean
1002write_method_signature(IDL_tree method_tree, FILE *outfile, int mode,
1003 const char *className)
1004{
1005 struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
1006 gboolean no_generated_args = TRUE;
1007 gboolean op_notxpcom =
1008 (IDL_tree_property_get(op->ident, "notxpcom") != NULL);
1009 const char *name;
1010 IDL_tree iter;
1011
1012 if (mode == AS_DECL) {
1013 if (op_notxpcom) {
1014 fputs("NS_IMETHOD_(", outfile);
1015 if (!write_type(op->op_type_spec, FALSE, outfile))
1016 return FALSE;
1017 fputc(')', outfile);
1018 } else {
1019 fputs("NS_IMETHOD", outfile);
1020 }
1021 fputc(' ', outfile);
1022 }
1023 else if (mode == AS_IMPL) {
1024 if (op_notxpcom) {
1025 fputs("NS_IMETHODIMP_(", outfile);
1026 if (!write_type(op->op_type_spec, FALSE, outfile))
1027 return FALSE;
1028 fputc(')', outfile);
1029 } else {
1030 fputs("NS_IMETHODIMP", outfile);
1031 }
1032 fputc(' ', outfile);
1033 }
1034 name = IDL_IDENT(op->ident).str;
1035 if (mode == AS_IMPL) {
1036 fprintf(outfile, "%s::%c%s(", className, toupper(*name), name + 1);
1037 } else {
1038 fprintf(outfile, "%c%s(", toupper(*name), name + 1);
1039 }
1040 for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) {
1041 if (mode == AS_DECL || mode == AS_IMPL) {
1042 if (!write_param(IDL_LIST(iter).data, outfile))
1043 return FALSE;
1044 } else {
1045 fputs(IDL_IDENT(IDL_PARAM_DCL(IDL_LIST(iter).data)
1046 .simple_declarator).str,
1047 outfile);
1048 }
1049 if ((IDL_LIST(iter).next ||
1050 (!op_notxpcom && op->op_type_spec) || op->f_varargs))
1051 fputs(", ", outfile);
1052 no_generated_args = FALSE;
1053 }
1054
1055 /* make IDL return value into trailing out argument */
1056 if (op->op_type_spec && !op_notxpcom) {
1057 IDL_tree fake_param = IDL_param_dcl_new(IDL_PARAM_OUT,
1058 op->op_type_spec,
1059 IDL_ident_new("_retval"));
1060 if (!fake_param)
1061 return FALSE;
1062 if (mode == AS_DECL || mode == AS_IMPL) {
1063 if (!write_param(fake_param, outfile))
1064 return FALSE;
1065 } else {
1066 fputs("_retval", outfile);
1067 }
1068 if (op->f_varargs)
1069 fputs(", ", outfile);
1070 no_generated_args = FALSE;
1071 }
1072
1073 /* varargs go last */
1074 if (op->f_varargs) {
1075 if (mode == AS_DECL || mode == AS_IMPL) {
1076 fputs("nsVarArgs *", outfile);
1077 }
1078 fputs("_varargs", outfile);
1079 no_generated_args = FALSE;
1080 }
1081
1082 /*
1083 * If generated method has no arguments, output 'void' to avoid C legacy
1084 * behavior of disabling type checking.
1085 */
1086 if (no_generated_args && mode == AS_DECL) {
1087 fputs("void", outfile);
1088 }
1089
1090 fputc(')', outfile);
1091
1092 return TRUE;
1093}
1094
1095/*
1096 * A method is an `operation', therefore a method decl is an `op dcl'.
1097 * I blame Elliot.
1098 */
1099static gboolean
1100op_dcl(TreeState *state)
1101{
1102 GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments;
1103
1104 /*
1105 * Verify that e.g. non-scriptable methods in [scriptable] interfaces
1106 * are declared so. Do this in a separate verification pass?
1107 */
1108 if (!verify_method_declaration(state->tree))
1109 return FALSE;
1110
1111 if (doc_comments != NULL) {
1112 write_indent(state->file);
1113 printlist(state->file, doc_comments);
1114 }
1115 xpidl_write_comment(state, 2);
1116
1117 write_indent(state->file);
1118 if (!write_method_signature(state->tree, state->file, AS_DECL, NULL))
1119 return FALSE;
1120 fputs(" = 0;\n\n", state->file);
1121
1122 return TRUE;
1123}
1124
1125static void
1126write_codefrag_line(gpointer data, gpointer user_data)
1127{
1128 TreeState *state = (TreeState *)user_data;
1129 const char *line = (const char *)data;
1130 fputs(line, state->file);
1131 fputc('\n', state->file);
1132}
1133
1134static gboolean
1135codefrag(TreeState *state)
1136{
1137 const char *desc = IDL_CODEFRAG(state->tree).desc;
1138 GSList *lines = IDL_CODEFRAG(state->tree).lines;
1139 guint fragment_length;
1140
1141 if (strcmp(desc, "C++") && /* libIDL bug? */ strcmp(desc, "C++\r")) {
1142 XPIDL_WARNING((state->tree, IDL_WARNING1,
1143 "ignoring '%%{%s' escape. "
1144 "(Use '%%{C++' to escape verbatim C++ code.)", desc));
1145
1146 return TRUE;
1147 }
1148
1149 /*
1150 * Emit #file directive to point debuggers back to the original .idl file
1151 * for the duration of the code fragment. We look at internal IDL node
1152 * properties _file, _line to do this; hopefully they won't change.
1153 *
1154 * _line seems to refer to the line immediately after the closing %}, so
1155 * we backtrack to get the proper line for the beginning of the block.
1156 */
1157 /*
1158 * Looks like getting this right means maintaining an accurate line
1159 * count of everything generated, so we can set the file back to the
1160 * correct line in the generated file afterwards. Skipping for now...
1161 */
1162
1163 fragment_length = g_slist_length(lines);
1164/* fprintf(state->file, "#line %d \"%s\"\n", */
1165/* state->tree->_line - fragment_length - 1, */
1166/* state->tree->_file); */
1167
1168 g_slist_foreach(lines, write_codefrag_line, (gpointer)state);
1169
1170 return TRUE;
1171}
1172
1173backend *
1174xpidl_header_dispatch(void)
1175{
1176 static backend result;
1177 static nodeHandler table[IDLN_LAST];
1178 static gboolean initialized = FALSE;
1179
1180 result.emit_prolog = header_prolog;
1181 result.emit_epilog = header_epilog;
1182
1183 if (!initialized) {
1184 table[IDLN_LIST] = list;
1185 table[IDLN_ATTR_DCL] = attr_dcl;
1186 table[IDLN_OP_DCL] = op_dcl;
1187 table[IDLN_FORWARD_DCL] = forward_dcl;
1188 table[IDLN_TYPE_ENUM] = do_enum;
1189 table[IDLN_INTERFACE] = interface;
1190 table[IDLN_CODEFRAG] = codefrag;
1191 table[IDLN_TYPE_DCL] = do_typedef;
1192 table[IDLN_CONST_DCL] = do_const_dcl;
1193 table[IDLN_NATIVE] = check_native;
1194 initialized = TRUE;
1195 }
1196
1197 result.dispatch_table = table;
1198 return &result;
1199}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use