VirtualBox

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

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

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

© 2023 Oracle
ContactPrivacy policyTerms of Use