On x86 compilers without fastcall, simulate it when invoking traces and un-simulate...
[wine-gecko.git] / xpcom / typelib / xpidl / xpidl_header.c
blobc4da8076a01abf9ab30f8ef46fc1526bc6421e4d
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
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 MPL, 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 MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * Generate XPCOM headers from XPIDL.
42 #include "xpidl.h"
43 #include <ctype.h>
45 #define AS_DECL 0
46 #define AS_CALL 1
47 #define AS_IMPL 2
49 static gboolean write_method_signature(IDL_tree method_tree, FILE *outfile,
50 int mode, const char *className);
51 static gboolean write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
52 gboolean getter,
53 int mode, const char *className);
55 static void
56 write_indent(FILE *outfile) {
57 fputs(" ", outfile);
60 static gboolean
61 header_prolog(TreeState *state)
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;
74 fputc('\n', state->file);
75 for (i = 0; i < len; i++) {
76 char *ident, *dot;
78 ident = (char *)g_slist_nth_data(state->base_includes, i);
80 /* suppress any trailing .extension */
82 /* XXX use g_basename instead ? ? */
84 dot = strrchr(ident, '.');
85 if (dot != NULL)
86 *dot = '\0';
89 /* begin include guard */
90 fprintf(state->file,
91 "\n#ifndef __gen_%s_h__\n",
92 ident);
94 fprintf(state->file, "#include \"%s.h\"\n",
95 (char *)g_slist_nth_data(state->base_includes, i));
97 fprintf(state->file, "#endif\n");
100 if (i > 0)
101 fputc('\n', state->file);
104 * Support IDL files that don't include a root IDL file that defines
105 * NS_NO_VTABLE.
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");
113 return TRUE;
116 static gboolean
117 header_epilog(TreeState *state)
119 const char *define = xpidl_basename(state->basename);
120 fprintf(state->file, "\n#endif /* __gen_%s_h__ */\n", define);
121 return TRUE;
124 static void
125 write_classname_iid_define(FILE *file, const char *className)
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;
135 while (*iidName)
136 fputc(toupper(*iidName++), file);
137 fputs("_IID", file);
140 static gboolean
141 interface(TreeState *state)
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, scriptable, deprecated;
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;
156 if (!verify_interface_declaration(iface))
157 return FALSE;
159 #define FAIL do {ok = FALSE; goto out;} while(0)
161 fprintf(state->file, "\n/* starting interface: %s */\n",
162 className);
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);
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;
181 * Parse uuid and then output resulting nsID to string, to validate
182 * uuid and normalize resulting .h files.
184 if (!xpidl_parse_iid(&id, iid)) {
185 IDL_tree_error(state->tree, "cannot parse IID %s\n", iid);
186 FAIL;
188 if (!xpidl_sprint_iid(&id, iid_parsed)) {
189 IDL_tree_error(state->tree, "error formatting IID %s\n", iid);
190 FAIL;
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);
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;
216 if (doc_comments != NULL)
217 printlist(state->file, doc_comments);
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.
227 keepvtable = FALSE;
228 for (iter = IDL_INTERFACE(state->tree).body;
229 iter != NULL;
230 iter = IDL_LIST(iter).next)
232 IDL_tree data = IDL_LIST(iter).data;
233 if (IDL_NODE_TYPE(data) == IDLN_CODEFRAG)
234 keepvtable = TRUE;
237 scriptable = deprecated = FALSE;
238 if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable"))
239 scriptable = TRUE;
240 if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "deprecated"))
241 deprecated = TRUE;
243 /* The interface declaration itself. */
244 fprintf(state->file,
245 "class %s%s%s%s",
246 (keepvtable ? "" : "NS_NO_VTABLE "),
247 (scriptable ? "NS_SCRIPTABLE " : ""),
248 (deprecated ? "NS_DEPRECATED " : ""),
249 className);
251 if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
252 fputs(" : ", state->file);
253 if (IDL_LIST(iter).next != NULL) {
254 IDL_tree_error(iter,
255 "multiple inheritance is not supported by xpidl");
256 FAIL;
258 fprintf(state->file, "public %s", IDL_IDENT(IDL_LIST(iter).data).str);
260 fputs(" {\n"
261 " public: \n\n", state->file);
262 if (iid) {
263 fputs(" NS_DECLARE_STATIC_IID_ACCESSOR(", state->file);
264 write_classname_iid_define(state->file, className);
265 fputs(")\n\n", state->file);
268 orig = state->tree; /* It would be nice to remove this state-twiddling. */
270 state->tree = IDL_INTERFACE(iface).body;
272 if (state->tree && !xpidl_process_node(state))
273 FAIL;
275 fputs("};\n", state->file);
276 fputc('\n', state->file);
278 if (iid) {
279 fprintf(state->file, " NS_DEFINE_STATIC_IID_ACCESSOR(%s, ",
280 className);
281 write_classname_iid_define(state->file, className);
282 fputs(")\n\n", state->file);
286 * #define NS_DECL_NSIFOO - create method prototypes that can be used in
287 * class definitions that support this interface.
289 * Walk the tree explicitly to prototype a reworking of xpidl to get rid of
290 * the callback mechanism.
292 state->tree = orig;
293 fputs("/* Use this macro when declaring classes that implement this "
294 "interface. */\n", state->file);
295 fputs("#define NS_DECL_", state->file);
296 classNameUpper = xpidl_strdup(className);
297 for (cp = classNameUpper; *cp != '\0'; cp++)
298 *cp = toupper(*cp);
299 fprintf(state->file, "%s \\\n", classNameUpper);
300 if (IDL_INTERFACE(state->tree).body == NULL) {
301 write_indent(state->file);
302 fputs("/* no methods! */\n", state->file);
305 for (iter = IDL_INTERFACE(state->tree).body;
306 iter != NULL;
307 iter = IDL_LIST(iter).next)
309 IDL_tree data = IDL_LIST(iter).data;
311 switch(IDL_NODE_TYPE(data)) {
312 case IDLN_OP_DCL:
313 write_indent(state->file);
314 write_method_signature(data, state->file, AS_DECL, NULL);
315 break;
317 case IDLN_ATTR_DCL:
318 write_indent(state->file);
319 if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
320 FAIL;
321 if (!IDL_ATTR_DCL(data).f_readonly) {
322 fputs("; \\\n", state->file); /* Terminate the previous one. */
323 write_indent(state->file);
324 if (!write_attr_accessor(data, state->file,
325 FALSE, AS_DECL, NULL))
326 FAIL;
327 /* '; \n' at end will clean up. */
329 break;
331 case IDLN_CONST_DCL:
332 /* ignore it here; it doesn't contribute to the macro. */
333 continue;
335 case IDLN_CODEFRAG:
336 XPIDL_WARNING((iter, IDL_WARNING1,
337 "%%{ .. %%} code fragment within interface "
338 "ignored when generating NS_DECL_%s macro; "
339 "if the code fragment contains method "
340 "declarations, the macro probably isn't "
341 "complete.", classNameUpper));
342 continue;
344 default:
345 IDL_tree_error(iter,
346 "unexpected node type %d! "
347 "Please file a bug against the xpidl component.",
348 IDL_NODE_TYPE(data));
349 FAIL;
352 if (IDL_LIST(iter).next != NULL) {
353 fprintf(state->file, "; \\\n");
354 } else {
355 fprintf(state->file, "; \n");
358 fputc('\n', state->file);
360 /* XXX abstract above and below into one function? */
362 * #define NS_FORWARD_NSIFOO - create forwarding methods that can delegate
363 * behavior from in implementation to another object. As generated by
364 * idlc.
366 fprintf(state->file,
367 "/* Use this macro to declare functions that forward the "
368 "behavior of this interface to another object. */\n"
369 "#define NS_FORWARD_%s(_to) \\\n",
370 classNameUpper);
371 if (IDL_INTERFACE(state->tree).body == NULL) {
372 write_indent(state->file);
373 fputs("/* no methods! */\n", state->file);
376 for (iter = IDL_INTERFACE(state->tree).body;
377 iter != NULL;
378 iter = IDL_LIST(iter).next)
380 IDL_tree data = IDL_LIST(iter).data;
382 switch(IDL_NODE_TYPE(data)) {
383 case IDLN_OP_DCL:
384 write_indent(state->file);
385 write_method_signature(data, state->file, AS_DECL, NULL);
386 fputs(" { return _to ", state->file);
387 write_method_signature(data, state->file, AS_CALL, NULL);
388 break;
390 case IDLN_ATTR_DCL:
391 write_indent(state->file);
392 if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
393 FAIL;
394 fputs(" { return _to ", state->file);
395 if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL))
396 FAIL;
397 if (!IDL_ATTR_DCL(data).f_readonly) {
398 fputs("; } \\\n", state->file); /* Terminate the previous one. */
399 write_indent(state->file);
400 if (!write_attr_accessor(data, state->file,
401 FALSE, AS_DECL, NULL))
402 FAIL;
403 fputs(" { return _to ", state->file);
404 if (!write_attr_accessor(data, state->file,
405 FALSE, AS_CALL, NULL))
406 FAIL;
407 /* '; } \n' at end will clean up. */
409 break;
411 case IDLN_CONST_DCL:
412 case IDLN_CODEFRAG:
413 continue;
415 default:
416 FAIL;
419 if (IDL_LIST(iter).next != NULL) {
420 fprintf(state->file, "; } \\\n");
421 } else {
422 fprintf(state->file, "; } \n");
425 fputc('\n', state->file);
428 /* XXX abstract above and below into one function? */
430 * #define NS_FORWARD_SAFE_NSIFOO - create forwarding methods that can delegate
431 * behavior from in implementation to another object. As generated by
432 * idlc.
434 fprintf(state->file,
435 "/* Use this macro to declare functions that forward the "
436 "behavior of this interface to another object in a safe way. */\n"
437 "#define NS_FORWARD_SAFE_%s(_to) \\\n",
438 classNameUpper);
439 if (IDL_INTERFACE(state->tree).body == NULL) {
440 write_indent(state->file);
441 fputs("/* no methods! */\n", state->file);
444 for (iter = IDL_INTERFACE(state->tree).body;
445 iter != NULL;
446 iter = IDL_LIST(iter).next)
448 IDL_tree data = IDL_LIST(iter).data;
450 switch(IDL_NODE_TYPE(data)) {
451 case IDLN_OP_DCL:
452 write_indent(state->file);
453 write_method_signature(data, state->file, AS_DECL, NULL);
454 fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
455 write_method_signature(data, state->file, AS_CALL, NULL);
456 break;
458 case IDLN_ATTR_DCL:
459 write_indent(state->file);
460 if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
461 FAIL;
462 fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
463 if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL))
464 FAIL;
465 if (!IDL_ATTR_DCL(data).f_readonly) {
466 fputs("; } \\\n", state->file); /* Terminate the previous one. */
467 write_indent(state->file);
468 if (!write_attr_accessor(data, state->file,
469 FALSE, AS_DECL, NULL))
470 FAIL;
471 fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
472 if (!write_attr_accessor(data, state->file,
473 FALSE, AS_CALL, NULL))
474 FAIL;
475 /* '; } \n' at end will clean up. */
477 break;
479 case IDLN_CONST_DCL:
480 case IDLN_CODEFRAG:
481 continue;
483 default:
484 FAIL;
487 if (IDL_LIST(iter).next != NULL) {
488 fprintf(state->file, "; } \\\n");
489 } else {
490 fprintf(state->file, "; } \n");
493 fputc('\n', state->file);
496 * Build a sample implementation template.
498 if (strlen(className) >= 3 && className[2] == 'I') {
499 classNameImpl = xpidl_strdup(className);
500 if (!classNameImpl)
501 FAIL;
502 memmove(&classNameImpl[2], &classNameImpl[3], strlen(classNameImpl) - 2);
503 } else {
504 classNameImpl = xpidl_strdup("_MYCLASS_");
505 if (!classNameImpl)
506 FAIL;
509 fputs("#if 0\n"
510 "/* Use the code below as a template for the "
511 "implementation class for this interface. */\n"
512 "\n"
513 "/* Header file */"
514 "\n",
515 state->file);
516 fprintf(state->file, "class %s : public %s\n", classNameImpl, className);
517 fputs("{\n"
518 "public:\n", state->file);
519 write_indent(state->file);
520 fputs("NS_DECL_ISUPPORTS\n", state->file);
521 write_indent(state->file);
522 fprintf(state->file, "NS_DECL_%s\n", classNameUpper);
523 fputs("\n", state->file);
524 write_indent(state->file);
525 fprintf(state->file, "%s();\n", classNameImpl);
526 fputs("\n"
527 "private:\n", state->file);
528 write_indent(state->file);
529 fprintf(state->file, "~%s();\n", classNameImpl);
530 fputs("\n"
531 "protected:\n", state->file);
532 write_indent(state->file);
533 fputs("/* additional members */\n", state->file);
534 fputs("};\n\n", state->file);
536 fputs("/* Implementation file */\n", state->file);
538 fprintf(state->file,
539 "NS_IMPL_ISUPPORTS1(%s, %s)\n", classNameImpl, className);
540 fputs("\n", state->file);
542 fprintf(state->file, "%s::%s()\n", classNameImpl, classNameImpl);
543 fputs("{\n", state->file);
544 write_indent(state->file);
545 fputs("/* member initializers and constructor code */\n", state->file);
546 fputs("}\n\n", state->file);
548 fprintf(state->file, "%s::~%s()\n", classNameImpl, classNameImpl);
549 fputs("{\n", state->file);
550 write_indent(state->file);
551 fputs("/* destructor code */\n", state->file);
552 fputs("}\n\n", state->file);
554 for (iter = IDL_INTERFACE(state->tree).body;
555 iter != NULL;
556 iter = IDL_LIST(iter).next)
558 IDL_tree data = IDL_LIST(iter).data;
560 switch(IDL_NODE_TYPE(data)) {
561 case IDLN_OP_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;
568 write_method_signature(data, state->file, AS_IMPL, classNameImpl);
569 fputs("\n{\n", state->file);
570 write_indent(state->file);
571 write_indent(state->file);
572 fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
573 "}\n"
574 "\n", state->file);
575 break;
577 case IDLN_ATTR_DCL:
578 /* It would be nice to remove this state-twiddling. */
579 orig = state->tree;
580 state->tree = data;
581 xpidl_write_comment(state, 0);
582 state->tree = orig;
584 if (!write_attr_accessor(data, state->file, TRUE,
585 AS_IMPL, classNameImpl))
586 FAIL;
587 fputs("\n{\n", state->file);
588 write_indent(state->file);
589 write_indent(state->file);
590 fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
591 "}\n", state->file);
593 if (!IDL_ATTR_DCL(data).f_readonly) {
594 if (!write_attr_accessor(data, state->file, FALSE,
595 AS_IMPL, classNameImpl))
596 FAIL;
597 fputs("\n{\n", state->file);
598 write_indent(state->file);
599 write_indent(state->file);
600 fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
601 "}\n", state->file);
603 fputs("\n", state->file);
604 break;
606 case IDLN_CONST_DCL:
607 case IDLN_CODEFRAG:
608 continue;
610 default:
611 FAIL;
615 fputs("/* End of implementation class template. */\n"
616 "#endif\n"
617 "\n", state->file);
619 #undef FAIL
621 out:
622 if (classNameUpper)
623 free(classNameUpper);
624 if (classNameImpl)
625 free(classNameImpl);
626 return ok;
629 static gboolean
630 list(TreeState *state)
632 IDL_tree iter;
633 for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
634 state->tree = IDL_LIST(iter).data;
635 if (!xpidl_process_node(state))
636 return FALSE;
638 return TRUE;
641 static gboolean
642 write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile)
644 if (!type_tree) {
645 fputs("void", outfile);
646 return TRUE;
649 switch (IDL_NODE_TYPE(type_tree)) {
650 case IDLN_TYPE_INTEGER: {
651 gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed;
652 switch (IDL_TYPE_INTEGER(type_tree).f_type) {
653 case IDL_INTEGER_TYPE_SHORT:
654 fputs(sign ? "PRInt16" : "PRUint16", outfile);
655 break;
656 case IDL_INTEGER_TYPE_LONG:
657 fputs(sign ? "PRInt32" : "PRUint32", outfile);
658 break;
659 case IDL_INTEGER_TYPE_LONGLONG:
660 fputs(sign ? "PRInt64" : "PRUint64", outfile);
661 break;
662 default:
663 g_error("Unknown integer type %d\n",
664 IDL_TYPE_INTEGER(type_tree).f_type);
665 return FALSE;
667 break;
669 case IDLN_TYPE_CHAR:
670 fputs("char", outfile);
671 break;
672 case IDLN_TYPE_WIDE_CHAR:
673 fputs("PRUnichar", outfile); /* wchar_t? */
674 break;
675 case IDLN_TYPE_WIDE_STRING:
676 fputs("PRUnichar *", outfile);
677 break;
678 case IDLN_TYPE_STRING:
679 fputs("char *", outfile);
680 break;
681 case IDLN_TYPE_BOOLEAN:
682 fputs("PRBool", outfile);
683 break;
684 case IDLN_TYPE_OCTET:
685 fputs("PRUint8", outfile);
686 break;
687 case IDLN_TYPE_FLOAT:
688 switch (IDL_TYPE_FLOAT(type_tree).f_type) {
689 case IDL_FLOAT_TYPE_FLOAT:
690 fputs("float", outfile);
691 break;
692 case IDL_FLOAT_TYPE_DOUBLE:
693 fputs("double", outfile);
694 break;
695 /* XXX 'long double' just ignored, or what? */
696 default:
697 fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
698 break;
700 break;
701 case IDLN_IDENT:
702 if (UP_IS_NATIVE(type_tree)) {
703 if (IDL_tree_property_get(type_tree, "domstring") ||
704 IDL_tree_property_get(type_tree, "astring")) {
705 fputs("nsAString", outfile);
706 } else if (IDL_tree_property_get(type_tree, "utf8string")) {
707 fputs("nsACString", outfile);
708 } else if (IDL_tree_property_get(type_tree, "cstring")) {
709 fputs("nsACString", outfile);
710 } else {
711 fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile);
713 if (IDL_tree_property_get(type_tree, "ptr")) {
714 fputs(" *", outfile);
715 } else if (IDL_tree_property_get(type_tree, "ref")) {
716 fputs(" &", outfile);
718 } else {
719 fputs(IDL_IDENT(type_tree).str, outfile);
721 if (UP_IS_AGGREGATE(type_tree))
722 fputs(" *", outfile);
723 break;
724 default:
725 fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
726 break;
728 return TRUE;
732 * An attribute declaration looks like:
734 * [ IDL_ATTR_DCL]
735 * - param_type_spec [IDL_TYPE_* or NULL for void]
736 * - simple_declarations [IDL_LIST]
737 * - data [IDL_IDENT]
738 * - next [IDL_LIST or NULL if no more idents]
739 * - data [IDL_IDENT]
742 #define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data))
743 #define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec)
744 #define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree)))
745 #define ATTR_DECLS(tree) (IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data)
748 * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)'
749 * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)'
750 * AS_CALL writes 'foo(bar, sil)'
752 static gboolean
753 write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
754 gboolean getter, int mode, const char *className)
756 char *attrname = ATTR_IDENT(attr_tree).str;
757 const char *binaryname;
758 IDL_tree ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data;
760 if (mode == AS_DECL) {
761 if (IDL_tree_property_get(ident, "deprecated"))
762 fputs("NS_DEPRECATED ", outfile);
763 if (is_method_scriptable(attr_tree, ident))
764 fputs("NS_SCRIPTABLE ", outfile);
766 fputs("NS_IMETHOD ", outfile);
767 } else if (mode == AS_IMPL) {
768 fprintf(outfile, "NS_IMETHODIMP %s::", className);
770 fprintf(outfile, "%cet",
771 getter ? 'G' : 'S');
772 binaryname = IDL_tree_property_get(ATTR_DECLS(attr_tree), "binaryname");
773 if (binaryname) {
774 fprintf(outfile, "%s(",
775 binaryname);
776 } else {
777 fprintf(outfile, "%c%s(",
778 toupper(*attrname),
779 attrname + 1);
781 if (mode == AS_DECL || mode == AS_IMPL) {
782 /* Setters for string, wstring, nsid, domstring, utf8string,
783 * cstring and astring get const.
785 if (!getter &&
786 (IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_STRING ||
787 IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_WIDE_STRING ||
788 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "nsid") ||
789 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring") ||
790 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "utf8string") ||
791 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "cstring") ||
792 IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "astring")))
794 fputs("const ", outfile);
797 if (!write_type(ATTR_TYPE_DECL(attr_tree), getter, outfile))
798 return FALSE;
799 fprintf(outfile, "%s%s",
800 (STARRED_TYPE(attr_tree) ? "" : " "),
801 (getter && !DIPPER_TYPE(ATTR_TYPE_DECL(attr_tree)))? "*" : "");
803 fprintf(outfile, "a%c%s)", toupper(attrname[0]), attrname + 1);
804 return TRUE;
807 static gboolean
808 attr_dcl(TreeState *state)
810 GSList *doc_comments;
812 if (!verify_attribute_declaration(state->tree))
813 return FALSE;
815 doc_comments =
816 IDL_IDENT(IDL_LIST(IDL_ATTR_DCL
817 (state->tree).simple_declarations).data).comments;
819 if (doc_comments != NULL) {
820 write_indent(state->file);
821 printlist(state->file, doc_comments);
825 * XXX lists of attributes with the same type, e.g.
826 * attribute string foo, bar sil;
827 * are legal IDL... but we don't do anything with 'em.
829 if (IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).next != NULL) {
830 XPIDL_WARNING((state->tree, IDL_WARNING1,
831 "multiple attributes in a single declaration aren't "
832 "currently supported by xpidl"));
835 xpidl_write_comment(state, 2);
837 write_indent(state->file);
838 if (!write_attr_accessor(state->tree, state->file, TRUE, AS_DECL, NULL))
839 return FALSE;
840 fputs(" = 0;\n", state->file);
842 if (!IDL_ATTR_DCL(state->tree).f_readonly) {
843 write_indent(state->file);
844 if (!write_attr_accessor(state->tree, state->file, FALSE, AS_DECL, NULL))
845 return FALSE;
846 fputs(" = 0;\n", state->file);
848 fputc('\n', state->file);
850 return TRUE;
853 static gboolean
854 do_enum(TreeState *state)
856 IDL_tree_error(state->tree, "enums not supported, "
857 "see http://bugzilla.mozilla.org/show_bug.cgi?id=8781");
858 return FALSE;
861 static gboolean
862 do_const_dcl(TreeState *state)
864 struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree);
865 const char *name = IDL_IDENT(dcl->ident).str;
866 gboolean is_signed;
867 GSList *doc_comments = IDL_IDENT(dcl->ident).comments;
868 IDL_tree real_type;
869 const char *const_format;
871 if (!verify_const_declaration(state->tree))
872 return FALSE;
874 if (doc_comments != NULL) {
875 write_indent(state->file);
876 printlist(state->file, doc_comments);
879 /* Could be a typedef; try to map it to the real type. */
880 real_type = find_underlying_type(dcl->const_type);
881 real_type = real_type ? real_type : dcl->const_type;
882 is_signed = IDL_TYPE_INTEGER(real_type).f_signed;
884 const_format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "uU";
885 write_indent(state->file);
886 fprintf(state->file, "enum { %s = ", name);
887 fprintf(state->file, const_format, IDL_INTEGER(dcl->const_exp).value);
888 fprintf(state->file, " };\n\n");
890 return TRUE;
893 static gboolean
894 do_typedef(TreeState *state)
896 IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec;
897 IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls;
898 IDL_tree complex;
899 GSList *doc_comments;
901 if (IDL_NODE_TYPE(type) == IDLN_TYPE_SEQUENCE) {
902 XPIDL_WARNING((state->tree, IDL_WARNING1,
903 "sequences not supported, ignored"));
904 } else {
905 if (IDL_NODE_TYPE(complex = IDL_LIST(dcls).data) == IDLN_TYPE_ARRAY) {
906 IDL_tree dim = IDL_TYPE_ARRAY(complex).size_list;
907 doc_comments = IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).comments;
909 if (doc_comments != NULL)
910 printlist(state->file, doc_comments);
912 fputs("typedef ", state->file);
913 if (!write_type(type, FALSE, state->file))
914 return FALSE;
915 fputs(" ", state->file);
917 fprintf(state->file, "%s",
918 IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).str);
919 do {
920 fputc('[', state->file);
921 if (IDL_LIST(dim).data) {
922 fprintf(state->file, "%ld",
923 (long)IDL_INTEGER(IDL_LIST(dim).data).value);
925 fputc(']', state->file);
926 } while ((dim = IDL_LIST(dim).next) != NULL);
927 } else {
928 doc_comments = IDL_IDENT(IDL_LIST(dcls).data).comments;
930 if (doc_comments != NULL)
931 printlist(state->file, doc_comments);
933 fputs("typedef ", state->file);
934 if (!write_type(type, FALSE, state->file))
935 return FALSE;
936 fputs(" ", state->file);
937 fputs(IDL_IDENT(IDL_LIST(dcls).data).str, state->file);
939 fputs(";\n\n", state->file);
941 return TRUE;
945 * param generation:
946 * in string foo --> nsString *foo
947 * out string foo --> nsString **foo;
948 * inout string foo --> nsString **foo;
951 /* If notype is true, just write the param name. */
952 static gboolean
953 write_param(IDL_tree param_tree, FILE *outfile)
955 IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec;
956 gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN;
957 /* in string, wstring, nsid, domstring, utf8string, cstring and
958 * astring any explicitly marked [const] are const
961 if (is_in &&
962 (IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_STRING ||
963 IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_WIDE_STRING ||
964 IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
965 "const") ||
966 IDL_tree_property_get(param_type_spec, "nsid") ||
967 IDL_tree_property_get(param_type_spec, "domstring") ||
968 IDL_tree_property_get(param_type_spec, "utf8string") ||
969 IDL_tree_property_get(param_type_spec, "cstring") ||
970 IDL_tree_property_get(param_type_spec, "astring"))) {
971 fputs("const ", outfile);
973 else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT &&
974 IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
975 "shared")) {
976 fputs("const ", outfile);
979 if (!write_type(param_type_spec, !is_in, outfile))
980 return FALSE;
982 /* unless the type ended in a *, add a space */
983 if (!STARRED_TYPE(param_type_spec))
984 fputc(' ', outfile);
986 /* out and inout params get a bonus '*' (unless this is type that has a
987 * 'dipper' class that is passed in to receive 'out' data)
989 if (IDL_PARAM_DCL(param_tree).attr != IDL_PARAM_IN &&
990 !DIPPER_TYPE(param_type_spec)) {
991 fputc('*', outfile);
993 /* arrays get a bonus * too */
994 /* XXX Should this be a leading '*' or a trailing "[]" ?*/
995 if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
996 "array"))
997 fputc('*', outfile);
999 fputs(IDL_IDENT(IDL_PARAM_DCL(param_tree).simple_declarator).str, outfile);
1001 if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT) {
1002 fputs(" NS_OUTPARAM", outfile);
1003 } else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_INOUT) {
1004 fputs(" NS_INOUTPARAM", outfile);
1007 return TRUE;
1011 * A forward declaration, usually an interface.
1013 static gboolean
1014 forward_dcl(TreeState *state)
1016 IDL_tree iface = state->tree;
1017 const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str;
1019 if (!className)
1020 return FALSE;
1022 fprintf(state->file, "class %s; /* forward declaration */\n\n", className);
1023 return TRUE;
1027 * Shared between the interface class declaration and the NS_DECL_IFOO macro
1028 * provided to aid declaration of implementation classes.
1029 * mode...
1030 * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)'
1031 * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)'
1032 * AS_CALL writes 'foo(bar, sil)'
1034 static gboolean
1035 write_method_signature(IDL_tree method_tree, FILE *outfile, int mode,
1036 const char *className)
1038 struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
1039 gboolean no_generated_args = TRUE;
1040 gboolean op_notxpcom =
1041 (IDL_tree_property_get(op->ident, "notxpcom") != NULL);
1042 const char *name;
1043 const char *binaryname;
1044 IDL_tree iter;
1046 if (mode == AS_DECL) {
1047 if (IDL_tree_property_get(op->ident, "deprecated"))
1048 fputs("NS_DEPRECATED ", outfile);
1049 if (is_method_scriptable(method_tree, op->ident))
1050 fputs("NS_SCRIPTABLE ", outfile);
1052 if (op_notxpcom) {
1053 fputs("NS_IMETHOD_(", outfile);
1054 if (!write_type(op->op_type_spec, FALSE, outfile))
1055 return FALSE;
1056 fputc(')', outfile);
1057 } else {
1058 fputs("NS_IMETHOD", outfile);
1060 fputc(' ', outfile);
1062 else if (mode == AS_IMPL) {
1063 if (op_notxpcom) {
1064 fputs("NS_IMETHODIMP_(", outfile);
1065 if (!write_type(op->op_type_spec, FALSE, outfile))
1066 return FALSE;
1067 fputc(')', outfile);
1068 } else {
1069 fputs("NS_IMETHODIMP", outfile);
1071 fputc(' ', outfile);
1073 name = IDL_IDENT(op->ident).str;
1074 if (mode == AS_IMPL) {
1075 fprintf(outfile, "%s::", className);
1077 binaryname = IDL_tree_property_get(op->ident, "binaryname");
1078 if (binaryname) {
1079 fprintf(outfile, "%s(", binaryname);
1080 } else {
1081 fprintf(outfile, "%c%s(", toupper(*name), name + 1);
1083 for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) {
1084 if (mode == AS_DECL || mode == AS_IMPL) {
1085 if (!write_param(IDL_LIST(iter).data, outfile))
1086 return FALSE;
1087 } else {
1088 fputs(IDL_IDENT(IDL_PARAM_DCL(IDL_LIST(iter).data)
1089 .simple_declarator).str,
1090 outfile);
1092 if ((IDL_LIST(iter).next ||
1093 (!op_notxpcom && op->op_type_spec) || op->f_varargs))
1094 fputs(", ", outfile);
1095 no_generated_args = FALSE;
1098 /* make IDL return value into trailing out argument */
1099 if (op->op_type_spec && !op_notxpcom) {
1100 IDL_tree fake_param = IDL_param_dcl_new(IDL_PARAM_OUT,
1101 op->op_type_spec,
1102 IDL_ident_new("_retval"));
1103 if (!fake_param)
1104 return FALSE;
1105 if (mode == AS_DECL || mode == AS_IMPL) {
1106 if (!write_param(fake_param, outfile))
1107 return FALSE;
1108 } else {
1109 fputs("_retval", outfile);
1111 if (op->f_varargs)
1112 fputs(", ", outfile);
1113 no_generated_args = FALSE;
1116 /* varargs go last */
1117 if (op->f_varargs) {
1118 if (mode == AS_DECL || mode == AS_IMPL) {
1119 fputs("nsVarArgs *", outfile);
1121 fputs("_varargs", outfile);
1122 no_generated_args = FALSE;
1126 * If generated method has no arguments, output 'void' to avoid C legacy
1127 * behavior of disabling type checking.
1129 if (no_generated_args && mode == AS_DECL) {
1130 fputs("void", outfile);
1133 fputc(')', outfile);
1135 return TRUE;
1139 * A method is an `operation', therefore a method decl is an `op dcl'.
1140 * I blame Elliot.
1142 static gboolean
1143 op_dcl(TreeState *state)
1145 GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments;
1148 * Verify that e.g. non-scriptable methods in [scriptable] interfaces
1149 * are declared so. Do this in a separate verification pass?
1151 if (!verify_method_declaration(state->tree))
1152 return FALSE;
1154 if (doc_comments != NULL) {
1155 write_indent(state->file);
1156 printlist(state->file, doc_comments);
1158 xpidl_write_comment(state, 2);
1160 write_indent(state->file);
1161 if (!write_method_signature(state->tree, state->file, AS_DECL, NULL))
1162 return FALSE;
1163 fputs(" = 0;\n\n", state->file);
1165 return TRUE;
1168 static void
1169 write_codefrag_line(gpointer data, gpointer user_data)
1171 TreeState *state = (TreeState *)user_data;
1172 const char *line = (const char *)data;
1173 fputs(line, state->file);
1174 fputc('\n', state->file);
1177 static gboolean
1178 codefrag(TreeState *state)
1180 const char *desc = IDL_CODEFRAG(state->tree).desc;
1181 GSList *lines = IDL_CODEFRAG(state->tree).lines;
1182 guint fragment_length;
1184 if (strcmp(desc, "C++") && /* libIDL bug? */ strcmp(desc, "C++\r")) {
1185 XPIDL_WARNING((state->tree, IDL_WARNING1,
1186 "ignoring '%%{%s' escape. "
1187 "(Use '%%{C++' to escape verbatim C++ code.)", desc));
1189 return TRUE;
1193 * Emit #file directive to point debuggers back to the original .idl file
1194 * for the duration of the code fragment. We look at internal IDL node
1195 * properties _file, _line to do this; hopefully they won't change.
1197 * _line seems to refer to the line immediately after the closing %}, so
1198 * we backtrack to get the proper line for the beginning of the block.
1201 * Looks like getting this right means maintaining an accurate line
1202 * count of everything generated, so we can set the file back to the
1203 * correct line in the generated file afterwards. Skipping for now...
1206 fragment_length = g_slist_length(lines);
1207 /* fprintf(state->file, "#line %d \"%s\"\n", */
1208 /* state->tree->_line - fragment_length - 1, */
1209 /* state->tree->_file); */
1211 g_slist_foreach(lines, write_codefrag_line, (gpointer)state);
1213 return TRUE;
1216 backend *
1217 xpidl_header_dispatch(void)
1219 static backend result;
1220 static nodeHandler table[IDLN_LAST];
1221 static gboolean initialized = FALSE;
1223 result.emit_prolog = header_prolog;
1224 result.emit_epilog = header_epilog;
1226 if (!initialized) {
1227 table[IDLN_LIST] = list;
1228 table[IDLN_ATTR_DCL] = attr_dcl;
1229 table[IDLN_OP_DCL] = op_dcl;
1230 table[IDLN_FORWARD_DCL] = forward_dcl;
1231 table[IDLN_TYPE_ENUM] = do_enum;
1232 table[IDLN_INTERFACE] = interface;
1233 table[IDLN_CODEFRAG] = codefrag;
1234 table[IDLN_TYPE_DCL] = do_typedef;
1235 table[IDLN_CONST_DCL] = do_const_dcl;
1236 table[IDLN_NATIVE] = check_native;
1237 initialized = TRUE;
1240 result.dispatch_table = table;
1241 return &result;