Bug 452317 - FeedConverter.js: QueryInterface should throw NS_ERROR_NO_INTERFACE...
[wine-gecko.git] / xpcom / idl-parser / header.py
blob26007e607b0e1278a1391ecbd71d09d1ee9d696d
1 #!/usr/bin/env python
2 # header.py - Generate C++ header files from IDL.
4 # ***** BEGIN LICENSE BLOCK *****
5 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 # The contents of this file are subject to the Mozilla Public License Version
8 # 1.1 (the "License"); you may not use this file except in compliance with
9 # the License. You may obtain a copy of the License at
10 # http://www.mozilla.org/MPL/
12 # Software distributed under the License is distributed on an "AS IS" basis,
13 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 # for the specific language governing rights and limitations under the
15 # License.
17 # The Original Code is mozilla.org code.
19 # The Initial Developer of the Original Code is
20 # Mozilla Foundation.
21 # Portions created by the Initial Developer are Copyright (C) 2008
22 # the Initial Developer. All Rights Reserved.
24 # Contributor(s):
25 # Benjamin Smedberg <benjamin@smedbergs.us>
27 # Alternatively, the contents of this file may be used under the terms of
28 # either of the GNU General Public License Version 2 or later (the "GPL"),
29 # or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 # in which case the provisions of the GPL or the LGPL are applicable instead
31 # of those above. If you wish to allow use of your version of this file only
32 # under the terms of either the GPL or the LGPL, and not to allow others to
33 # use your version of this file under the terms of the MPL, indicate your
34 # decision by deleting the provisions above and replace them with the notice
35 # and other provisions required by the GPL or the LGPL. If you do not delete
36 # the provisions above, a recipient may use your version of this file under
37 # the terms of any one of the MPL, the GPL or the LGPL.
39 # ***** END LICENSE BLOCK *****
41 """Print a C++ header file for the IDL files specified on the command line"""
43 import sys, os.path, re, xpidl
45 printdoccomments = False
47 if printdoccomments:
48 def printComments(fd, clist, indent):
49 for c in clist:
50 fd.write("%s%s\n" % (indent, c))
51 else:
52 def printComments(fd, clist, indent):
53 pass
55 def firstCap(str):
56 return str[0].upper() + str[1:]
58 def attributeParamName(a):
59 return "a" + firstCap(a.name)
61 def attributeNativeName(a, getter):
62 binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
63 return "%s%s" % (getter and 'Get' or 'Set', binaryname)
65 def attributeParamlist(a, getter):
66 return "%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
67 attributeParamName(a))
69 def attributeAsNative(a, getter):
70 scriptable = a.isScriptable() and "NS_SCRIPTABLE " or ""
71 params = {'scriptable': scriptable,
72 'binaryname': attributeNativeName(a, getter),
73 'paramlist': attributeParamlist(a, getter)}
74 return "%(scriptable)sNS_IMETHOD %(binaryname)s(%(paramlist)s)" % params
76 def methodNativeName(m):
77 return m.binaryname is not None and m.binaryname or firstCap(m.name)
79 def methodReturnType(m, macro):
80 """macro should be NS_IMETHOD or NS_IMETHODIMP"""
81 if m.notxpcom:
82 return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
83 else:
84 return macro
86 def methodAsNative(m):
87 scriptable = m.isScriptable() and "NS_SCRIPTABLE " or ""
89 return "%s%s %s(%s)" % (scriptable,
90 methodReturnType(m, 'NS_IMETHOD'),
91 methodNativeName(m),
92 paramlistAsNative(m.params,
93 m.realtype,
94 notxpcom=m.notxpcom))
96 def paramlistAsNative(l, rettype, notxpcom, empty='void'):
97 l = list(l)
98 if not notxpcom and rettype.name != 'void':
99 l.append(xpidl.Param(paramtype='out',
100 type=None,
101 name='_retval',
102 attlist=[],
103 location=None,
104 realtype=rettype))
106 if len(l) == 0:
107 return empty
109 return ", ".join([paramAsNative(p) for p in l])
111 def paramAsNative(p):
112 if p.paramtype == 'in':
113 typeannotate = ''
114 else:
115 typeannotate = ' NS_%sPARAM' % p.paramtype.upper()
117 return "%s%s%s" % (p.nativeType(),
118 p.name,
119 typeannotate)
121 def paramlistNames(l, rettype, notxpcom):
122 names = [p.name for p in l]
123 if not notxpcom and rettype.name != 'void':
124 names.append('_retval')
125 if len(names) == 0:
126 return ''
127 return ', '.join(names)
129 header = """/*
130 * DO NOT EDIT. THIS FILE IS GENERATED FROM %(filename)s
133 #ifndef __gen_%(basename)s_h__
134 #define __gen_%(basename)s_h__
137 include = """
138 #ifndef __gen_%(basename)s_h__
139 #include "%(basename)s.h"
140 #endif
143 header_end = """/* For IDL files that don't want to include root IDL files. */
144 #ifndef NS_NO_VTABLE
145 #define NS_NO_VTABLE
146 #endif
149 footer = """
150 #endif /* __gen_%(basename)s_h__ */
153 forward_decl = """class %(name)s; /* forward declaration */
157 def idl_basename(f):
158 """returns the base name of a file with the last extension stripped"""
159 return os.path.basename(f).rpartition('.')[0]
161 def print_header(idl, fd, filename):
162 fd.write(header % {'filename': filename,
163 'basename': idl_basename(filename)})
165 foundinc = False
166 for inc in idl.includes():
167 if not foundinc:
168 foundinc = True
169 fd.write('\n')
170 fd.write(include % {'basename': idl_basename(inc.filename)})
172 fd.write('\n')
173 fd.write(header_end)
175 for p in idl.productions:
176 if p.kind == 'include': continue
177 if p.kind == 'cdata':
178 fd.write(p.data)
179 continue
181 if p.kind == 'forward':
182 fd.write(forward_decl % {'name': p.name})
183 continue
184 if p.kind == 'interface':
185 write_interface(p, fd)
186 continue
187 if p.kind == 'typedef':
188 printComments(fd, p.doccomments, '')
189 fd.write("typedef %s %s;\n\n" % (p.realtype.nativeType('in'),
190 p.name))
192 fd.write(footer % {'basename': idl_basename(filename)})
194 iface_header = r"""
195 /* starting interface: %(name)s */
196 #define %(defname)s_IID_STR "%(iid)s"
198 #define %(defname)s_IID \
199 {0x%(m0)s, 0x%(m1)s, 0x%(m2)s, \
200 { %(m3joined)s }}
204 uuid_decoder = re.compile(r"""(?P<m0>[a-f0-9]{8})-
205 (?P<m1>[a-f0-9]{4})-
206 (?P<m2>[a-f0-9]{4})-
207 (?P<m3>[a-f0-9]{4})-
208 (?P<m4>[a-f0-9]{12})$""", re.X)
210 iface_prolog = """ {
211 public:
213 NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
217 iface_epilog = """};
219 NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
221 /* Use this macro when declaring classes that implement this interface. */
222 #define NS_DECL_%(macroname)s """
225 iface_forward = """
227 /* Use this macro to declare functions that forward the behavior of this interface to another object. */
228 #define NS_FORWARD_%(macroname)s(_to) """
230 iface_forward_safe = """
232 /* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
233 #define NS_FORWARD_SAFE_%(macroname)s(_to) """
235 iface_template_prolog = """
237 #if 0
238 /* Use the code below as a template for the implementation class for this interface. */
240 /* Header file */
241 class %(implclass)s : public %(name)s
243 public:
244 NS_DECL_ISUPPORTS
245 NS_DECL_%(macroname)s
247 %(implclass)s();
249 private:
250 ~%(implclass)s();
252 protected:
253 /* additional members */
256 /* Implementation file */
257 NS_IMPL_ISUPPORTS1(%(implclass)s, %(name)s)
259 %(implclass)s::%(implclass)s()
261 /* member initializers and constructor code */
264 %(implclass)s::~%(implclass)s()
266 /* destructor code */
271 example_tmpl = """%(returntype)s %(implclass)s::%(nativeName)s(%(paramList)s)
273 return NS_ERROR_NOT_IMPLEMENTED;
277 iface_template_epilog = """/* End of implementation class template. */
278 #endif
282 def write_interface(iface, fd):
283 if iface.namemap is None:
284 raise Exception("Interface was not resolved.")
286 def write_const_decl(c):
287 printComments(fd, c.doccomments, ' ')
289 basetype = c.basetype
290 value = c.getValue()
292 fd.write(" enum { %(name)s = %(value)s%(signed)s };\n\n" % {
293 'name': c.name,
294 'value': value,
295 'signed': (not basetype.signed) and 'U' or ''})
297 def write_method_decl(m):
298 printComments(fd, m.doccomments, ' ')
300 fd.write(" /* %s */\n" % m.toIDL())
301 fd.write(" %s = 0;\n\n" % methodAsNative(m))
303 def write_attr_decl(a):
304 printComments(fd, a.doccomments, ' ')
306 fd.write(" /* %s */\n" % a.toIDL());
308 fd.write(" %s = 0;\n" % attributeAsNative(a, True))
309 if not a.readonly:
310 fd.write(" %s = 0;\n" % attributeAsNative(a, False))
311 fd.write("\n")
313 defname = iface.name.upper()
314 if iface.name[0:2] == 'ns':
315 defname = 'NS_' + defname[2:]
317 names = uuid_decoder.match(iface.attributes.uuid).groupdict()
318 m3str = names['m3'] + names['m4']
319 names['m3joined'] = ", ".join(["0x%s" % m3str[i:i+2] for i in xrange(0, 16, 2)])
321 if iface.name[2] == 'I':
322 implclass = iface.name[:2] + iface.name[3:]
323 else:
324 implclass = '_MYCLASS_'
326 names.update({'defname': defname,
327 'macroname': iface.name.upper(),
328 'name': iface.name,
329 'iid': iface.attributes.uuid,
330 'implclass': implclass})
332 fd.write(iface_header % names)
334 printComments(fd, iface.doccomments, '')
336 fd.write("class ")
337 foundcdata = False
338 for m in iface.members:
339 if isinstance(m, xpidl.CDATA):
340 foundcdata = True
342 if not foundcdata:
343 fd.write("NS_NO_VTABLE ")
345 if iface.attributes.scriptable:
346 fd.write("NS_SCRIPTABLE ")
347 if iface.attributes.deprecated:
348 fd.write("NS_DEPRECATED ")
349 fd.write(iface.name)
350 if iface.base:
351 fd.write(" : public %s" % iface.base)
352 fd.write(iface_prolog % names)
353 for member in iface.members:
354 if isinstance(member, xpidl.ConstMember):
355 write_const_decl(member)
356 elif isinstance(member, xpidl.Attribute):
357 write_attr_decl(member)
358 elif isinstance(member, xpidl.Method):
359 write_method_decl(member)
360 elif isinstance(member, xpidl.CDATA):
361 fd.write(" %s" % member.data)
362 else:
363 raise Exception("Unexpected interface member: %s" % member)
365 fd.write(iface_epilog % names)
367 for member in iface.members:
368 if isinstance(member, xpidl.Attribute):
369 fd.write("\\\n %s; " % attributeAsNative(member, True))
370 if not member.readonly:
371 fd.write("\\\n %s; " % attributeAsNative(member, False))
372 elif isinstance(member, xpidl.Method):
373 fd.write("\\\n %s; " % methodAsNative(member))
374 if len(iface.members) == 0:
375 fd.write('\\\n /* no methods! */')
376 elif not member.kind in ('attribute', 'method'):
377 fd.write('\\')
379 fd.write(iface_forward % names)
381 def emitTemplate(tmpl):
382 for member in iface.members:
383 if isinstance(member, xpidl.Attribute):
384 fd.write(tmpl % {'asNative': attributeAsNative(member, True),
385 'nativeName': attributeNativeName(member, True),
386 'paramList': attributeParamName(member)})
387 if not member.readonly:
388 fd.write(tmpl % {'asNative': attributeAsNative(member, False),
389 'nativeName': attributeNativeName(member, False),
390 'paramList': attributeParamName(member)})
391 elif isinstance(member, xpidl.Method):
392 fd.write(tmpl % {'asNative': methodAsNative(member),
393 'nativeName': methodNativeName(member),
394 'paramList': paramlistNames(member.params, member.realtype, member.notxpcom)})
395 if len(iface.members) == 0:
396 fd.write('\\\n /* no methods! */')
397 elif not member.kind in ('attribute', 'method'):
398 fd.write('\\')
400 emitTemplate("\\\n %(asNative)s { return _to %(nativeName)s(%(paramList)s); } ")
402 fd.write(iface_forward_safe % names)
404 emitTemplate("\\\n %(asNative)s { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ")
406 fd.write(iface_template_prolog % names)
408 for member in iface.members:
409 if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA): continue
410 fd.write("/* %s */\n" % member.toIDL())
411 if isinstance(member, xpidl.Attribute):
412 fd.write(example_tmpl % {'implclass': implclass,
413 'returntype': 'NS_IMETHODIMP',
414 'nativeName': attributeNativeName(member, True),
415 'paramList': attributeParamlist(member, True)})
416 if not member.readonly:
417 fd.write(example_tmpl % {'implclass': implclass,
418 'returntype': 'NS_IMETHODIMP',
419 'nativeName': attributeNativeName(member, False),
420 'paramList': attributeParamlist(member, False)})
421 elif isinstance(member, xpidl.Method):
422 fd.write(example_tmpl % {'implclass': implclass,
423 'returntype': methodReturnType(member, 'NS_IMETHODIMP'),
424 'nativeName': methodNativeName(member),
425 'paramList': paramlistAsNative(member.params, member.realtype, notxpcom=member.notxpcom, empty='')})
426 fd.write('\n')
428 fd.write(iface_template_epilog)
430 if __name__ == '__main__':
431 from optparse import OptionParser
432 o = OptionParser()
433 o.add_option('-I', action='append', dest='incdirs', help="Directory to search for imported files", default=[])
434 o.add_option('--cachedir', dest='cachedir', help="Directory in which to cache lex/parse tables.", default='')
435 options, args = o.parse_args()
436 file, = args
438 if options.cachedir != '':
439 sys.path.append(options.cachedir)
441 p = xpidl.IDLParser(outputdir=options.cachedir)
442 idl = p.parse(open(file).read(), filename=file)
443 idl.resolve(options.incdirs, p)
444 print_header(idl, sys.stdout, file)