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
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.
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.
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
,
53 int mode
, const char *className
);
56 write_indent(FILE *outfile
) {
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
);
67 "\n#ifndef __gen_%s_h__\n"
68 "#define __gen_%s_h__\n",
70 if (state
->base_includes
!= NULL
) {
71 guint len
= g_slist_length(state
->base_includes
);
74 fputc('\n', state
->file
);
75 for (i
= 0; i
< len
; i
++) {
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
, '.');
89 /* begin include guard */
91 "\n#ifndef __gen_%s_h__\n",
94 fprintf(state
->file
, "#include \"%s.h\"\n",
95 (char *)g_slist_nth_data(state
->base_includes
, i
));
97 fprintf(state
->file
, "#endif\n");
101 fputc('\n', state
->file
);
104 * Support IDL files that don't include a root IDL file that defines
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"
117 header_epilog(TreeState
*state
)
119 const char *define
= xpidl_basename(state
->basename
);
120 fprintf(state
->file
, "\n#endif /* __gen_%s_h__ */\n", define
);
125 write_classname_iid_define(FILE *file
, const char *className
)
128 if (className
[0] == 'n' && className
[1] == 's') {
129 /* backcompat naming styles */
131 iidName
= className
+ 2;
136 fputc(toupper(*iidName
++), file
);
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
;
149 gboolean keepvtable
, scriptable
, deprecated
;
151 const char *name_space
;
153 char iid_parsed
[UUID_LENGTH
];
154 GSList
*doc_comments
= IDL_IDENT(IDL_INTERFACE(iface
).ident
).comments
;
156 if (!verify_interface_declaration(iface
))
159 #define FAIL do {ok = FALSE; goto out;} while(0)
161 fprintf(state
->file
, "\n/* starting interface: %s */\n",
164 name_space
= IDL_tree_property_get(IDL_INTERFACE(iface
).ident
, "namespace");
166 fprintf(state
->file
, "/* namespace: %s */\n",
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");
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
);
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
);
188 if (!xpidl_sprint_iid(&id
, iid_parsed
)) {
189 IDL_tree_error(state
->tree
, "error formatting IID %s\n", iid
);
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",
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
);
211 IDL_tree_error(state
->tree
, "interface %s lacks a uuid attribute\n",
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
228 for (iter
= IDL_INTERFACE(state
->tree
).body
;
230 iter
= IDL_LIST(iter
).next
)
232 IDL_tree data
= IDL_LIST(iter
).data
;
233 if (IDL_NODE_TYPE(data
) == IDLN_CODEFRAG
)
237 scriptable
= deprecated
= FALSE
;
238 if (IDL_tree_property_get(IDL_INTERFACE(iface
).ident
, "scriptable"))
240 if (IDL_tree_property_get(IDL_INTERFACE(iface
).ident
, "deprecated"))
243 /* The interface declaration itself. */
246 (keepvtable
? "" : "NS_NO_VTABLE "),
247 (scriptable
? "NS_SCRIPTABLE " : ""),
248 (deprecated
? "NS_DEPRECATED " : ""),
251 if ((iter
= IDL_INTERFACE(iface
).inheritance_spec
)) {
252 fputs(" : ", state
->file
);
253 if (IDL_LIST(iter
).next
!= NULL
) {
255 "multiple inheritance is not supported by xpidl");
258 fprintf(state
->file
, "public %s", IDL_IDENT(IDL_LIST(iter
).data
).str
);
261 " public: \n\n", state
->file
);
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
))
275 fputs("};\n", state
->file
);
276 fputc('\n', state
->file
);
279 fprintf(state
->file
, " NS_DEFINE_STATIC_IID_ACCESSOR(%s, ",
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.
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
++)
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
;
307 iter
= IDL_LIST(iter
).next
)
309 IDL_tree data
= IDL_LIST(iter
).data
;
311 switch(IDL_NODE_TYPE(data
)) {
313 write_indent(state
->file
);
314 write_method_signature(data
, state
->file
, AS_DECL
, NULL
);
318 write_indent(state
->file
);
319 if (!write_attr_accessor(data
, state
->file
, TRUE
, AS_DECL
, NULL
))
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
))
327 /* '; \n' at end will clean up. */
332 /* ignore it here; it doesn't contribute to the macro. */
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
));
346 "unexpected node type %d! "
347 "Please file a bug against the xpidl component.",
348 IDL_NODE_TYPE(data
));
352 if (IDL_LIST(iter
).next
!= NULL
) {
353 fprintf(state
->file
, "; \\\n");
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
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",
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
;
378 iter
= IDL_LIST(iter
).next
)
380 IDL_tree data
= IDL_LIST(iter
).data
;
382 switch(IDL_NODE_TYPE(data
)) {
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
);
391 write_indent(state
->file
);
392 if (!write_attr_accessor(data
, state
->file
, TRUE
, AS_DECL
, NULL
))
394 fputs(" { return _to ", state
->file
);
395 if (!write_attr_accessor(data
, state
->file
, TRUE
, AS_CALL
, NULL
))
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
))
403 fputs(" { return _to ", state
->file
);
404 if (!write_attr_accessor(data
, state
->file
,
405 FALSE
, AS_CALL
, NULL
))
407 /* '; } \n' at end will clean up. */
419 if (IDL_LIST(iter
).next
!= NULL
) {
420 fprintf(state
->file
, "; } \\\n");
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
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",
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
;
446 iter
= IDL_LIST(iter
).next
)
448 IDL_tree data
= IDL_LIST(iter
).data
;
450 switch(IDL_NODE_TYPE(data
)) {
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
);
459 write_indent(state
->file
);
460 if (!write_attr_accessor(data
, state
->file
, TRUE
, AS_DECL
, NULL
))
462 fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state
->file
);
463 if (!write_attr_accessor(data
, state
->file
, TRUE
, AS_CALL
, NULL
))
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
))
471 fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state
->file
);
472 if (!write_attr_accessor(data
, state
->file
,
473 FALSE
, AS_CALL
, NULL
))
475 /* '; } \n' at end will clean up. */
487 if (IDL_LIST(iter
).next
!= NULL
) {
488 fprintf(state
->file
, "; } \\\n");
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
);
502 memmove(&classNameImpl
[2], &classNameImpl
[3], strlen(classNameImpl
) - 2);
504 classNameImpl
= xpidl_strdup("_MYCLASS_");
510 "/* Use the code below as a template for the "
511 "implementation class for this interface. */\n"
516 fprintf(state
->file
, "class %s : public %s\n", classNameImpl
, className
);
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
);
527 "private:\n", state
->file
);
528 write_indent(state
->file
);
529 fprintf(state
->file
, "~%s();\n", classNameImpl
);
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
);
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
;
556 iter
= IDL_LIST(iter
).next
)
558 IDL_tree data
= IDL_LIST(iter
).data
;
560 switch(IDL_NODE_TYPE(data
)) {
562 /* It would be nice to remove this state-twiddling. */
565 xpidl_write_comment(state
, 0);
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"
578 /* It would be nice to remove this state-twiddling. */
581 xpidl_write_comment(state
, 0);
584 if (!write_attr_accessor(data
, state
->file
, TRUE
,
585 AS_IMPL
, classNameImpl
))
587 fputs("\n{\n", state
->file
);
588 write_indent(state
->file
);
589 write_indent(state
->file
);
590 fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
593 if (!IDL_ATTR_DCL(data
).f_readonly
) {
594 if (!write_attr_accessor(data
, state
->file
, FALSE
,
595 AS_IMPL
, classNameImpl
))
597 fputs("\n{\n", state
->file
);
598 write_indent(state
->file
);
599 write_indent(state
->file
);
600 fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
603 fputs("\n", state
->file
);
615 fputs("/* End of implementation class template. */\n"
623 free(classNameUpper
);
630 list(TreeState
*state
)
633 for (iter
= state
->tree
; iter
; iter
= IDL_LIST(iter
).next
) {
634 state
->tree
= IDL_LIST(iter
).data
;
635 if (!xpidl_process_node(state
))
642 write_type(IDL_tree type_tree
, gboolean is_out
, FILE *outfile
)
645 fputs("void", outfile
);
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
);
656 case IDL_INTEGER_TYPE_LONG
:
657 fputs(sign
? "PRInt32" : "PRUint32", outfile
);
659 case IDL_INTEGER_TYPE_LONGLONG
:
660 fputs(sign
? "PRInt64" : "PRUint64", outfile
);
663 g_error("Unknown integer type %d\n",
664 IDL_TYPE_INTEGER(type_tree
).f_type
);
670 fputs("char", outfile
);
672 case IDLN_TYPE_WIDE_CHAR
:
673 fputs("PRUnichar", outfile
); /* wchar_t? */
675 case IDLN_TYPE_WIDE_STRING
:
676 fputs("PRUnichar *", outfile
);
678 case IDLN_TYPE_STRING
:
679 fputs("char *", outfile
);
681 case IDLN_TYPE_BOOLEAN
:
682 fputs("PRBool", outfile
);
684 case IDLN_TYPE_OCTET
:
685 fputs("PRUint8", outfile
);
687 case IDLN_TYPE_FLOAT
:
688 switch (IDL_TYPE_FLOAT(type_tree
).f_type
) {
689 case IDL_FLOAT_TYPE_FLOAT
:
690 fputs("float", outfile
);
692 case IDL_FLOAT_TYPE_DOUBLE
:
693 fputs("double", outfile
);
695 /* XXX 'long double' just ignored, or what? */
697 fprintf(outfile
, "unknown_type_%d", IDL_NODE_TYPE(type_tree
));
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
);
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
);
719 fputs(IDL_IDENT(type_tree
).str
, outfile
);
721 if (UP_IS_AGGREGATE(type_tree
))
722 fputs(" *", outfile
);
725 fprintf(outfile
, "unknown_type_%d", IDL_NODE_TYPE(type_tree
));
732 * An attribute declaration looks like:
735 * - param_type_spec [IDL_TYPE_* or NULL for void]
736 * - simple_declarations [IDL_LIST]
738 * - next [IDL_LIST or NULL if no more idents]
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)'
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",
772 binaryname
= IDL_tree_property_get(ATTR_DECLS(attr_tree
), "binaryname");
774 fprintf(outfile
, "%s(",
777 fprintf(outfile
, "%c%s(",
781 if (mode
== AS_DECL
|| mode
== AS_IMPL
) {
782 /* Setters for string, wstring, nsid, domstring, utf8string,
783 * cstring and astring get const.
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
))
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);
808 attr_dcl(TreeState
*state
)
810 GSList
*doc_comments
;
812 if (!verify_attribute_declaration(state
->tree
))
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
))
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
))
846 fputs(" = 0;\n", state
->file
);
848 fputc('\n', state
->file
);
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");
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
;
867 GSList
*doc_comments
= IDL_IDENT(dcl
->ident
).comments
;
869 const char *const_format
;
871 if (!verify_const_declaration(state
->tree
))
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");
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
;
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"));
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
))
915 fputs(" ", state
->file
);
917 fprintf(state
->file
, "%s",
918 IDL_IDENT(IDL_TYPE_ARRAY(complex).ident
).str
);
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
);
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
))
936 fputs(" ", state
->file
);
937 fputs(IDL_IDENT(IDL_LIST(dcls
).data
).str
, state
->file
);
939 fputs(";\n\n", state
->file
);
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. */
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
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
,
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
,
976 fputs("const ", outfile
);
979 if (!write_type(param_type_spec
, !is_in
, outfile
))
982 /* unless the type ended in a *, add a space */
983 if (!STARRED_TYPE(param_type_spec
))
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
)) {
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
,
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
);
1011 * A forward declaration, usually an interface.
1014 forward_dcl(TreeState
*state
)
1016 IDL_tree iface
= state
->tree
;
1017 const char *className
= IDL_IDENT(IDL_FORWARD_DCL(iface
).ident
).str
;
1022 fprintf(state
->file
, "class %s; /* forward declaration */\n\n", className
);
1027 * Shared between the interface class declaration and the NS_DECL_IFOO macro
1028 * provided to aid declaration of implementation classes.
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)'
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
);
1043 const char *binaryname
;
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
);
1053 fputs("NS_IMETHOD_(", outfile
);
1054 if (!write_type(op
->op_type_spec
, FALSE
, outfile
))
1056 fputc(')', outfile
);
1058 fputs("NS_IMETHOD", outfile
);
1060 fputc(' ', outfile
);
1062 else if (mode
== AS_IMPL
) {
1064 fputs("NS_IMETHODIMP_(", outfile
);
1065 if (!write_type(op
->op_type_spec
, FALSE
, outfile
))
1067 fputc(')', outfile
);
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");
1079 fprintf(outfile
, "%s(", binaryname
);
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
))
1088 fputs(IDL_IDENT(IDL_PARAM_DCL(IDL_LIST(iter
).data
)
1089 .simple_declarator
).str
,
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
,
1102 IDL_ident_new("_retval"));
1105 if (mode
== AS_DECL
|| mode
== AS_IMPL
) {
1106 if (!write_param(fake_param
, outfile
))
1109 fputs("_retval", outfile
);
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
);
1139 * A method is an `operation', therefore a method decl is an `op dcl'.
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
))
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
))
1163 fputs(" = 0;\n\n", state
->file
);
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
);
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
));
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
);
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
;
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
;
1240 result
.dispatch_table
= table
;