~ubuntu-branches/ubuntu/quantal/enigmail/quantal-security

« back to all changes in this revision

Viewing changes to mozilla/xpcom/idl-parser/typelib.py

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2013-09-13 16:02:15 UTC
  • mfrom: (0.12.16)
  • Revision ID: package-import@ubuntu.com-20130913160215-u3g8nmwa0pdwagwc
Tags: 2:1.5.2-0ubuntu0.12.10.1
* New upstream release v1.5.2 for Thunderbird 24

* Build enigmail using a stripped down Thunderbird 17 build system, as it's
  now quite difficult to build the way we were doing previously, with the
  latest Firefox build system
* Add debian/patches/no_libxpcom.patch - Don't link against libxpcom, as it
  doesn't exist anymore (but exists in the build system)
* Add debian/patches/use_sdk.patch - Use the SDK version of xpt.py and
  friends
* Drop debian/patches/ipc-pipe_rename.diff (not needed anymore)
* Drop debian/patches/makefile_depth.diff (not needed anymore)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# typelib.py - Generate XPCOM typelib files from IDL.
 
3
#
 
4
# This Source Code Form is subject to the terms of the Mozilla Public
 
5
# License, v. 2.0. If a copy of the MPL was not distributed with this
 
6
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
7
 
 
8
"""Generate an XPIDL typelib for the IDL files specified on the command line"""
 
9
 
 
10
import os
 
11
import sys
 
12
import xpidl, xpt
 
13
 
 
14
# A map of xpidl.py types to xpt.py types
 
15
TypeMap = {
 
16
    # nsresult is not strictly an xpidl.py type, but it's useful here
 
17
    'nsresult':           xpt.Type.Tags.uint32,
 
18
    # builtins
 
19
    'boolean':            xpt.Type.Tags.boolean,
 
20
    'void':               xpt.Type.Tags.void,
 
21
    'int16_t':            xpt.Type.Tags.int16,
 
22
    'int32_t':            xpt.Type.Tags.int32,
 
23
    'int64_t':            xpt.Type.Tags.int64,
 
24
    'uint8_t':            xpt.Type.Tags.uint8,
 
25
    'uint16_t':           xpt.Type.Tags.uint16,
 
26
    'uint32_t':           xpt.Type.Tags.uint32,
 
27
    'uint64_t':           xpt.Type.Tags.uint64,
 
28
    'octet':              xpt.Type.Tags.uint8,
 
29
    'short':              xpt.Type.Tags.int16,
 
30
    'long':               xpt.Type.Tags.int32,
 
31
    'long long':          xpt.Type.Tags.int64,
 
32
    'unsigned short':     xpt.Type.Tags.uint16,
 
33
    'unsigned long':      xpt.Type.Tags.uint32,
 
34
    'unsigned long long': xpt.Type.Tags.uint64,
 
35
    'float':              xpt.Type.Tags.float,
 
36
    'double':             xpt.Type.Tags.double,
 
37
    'char':               xpt.Type.Tags.char,
 
38
    'string':             xpt.Type.Tags.char_ptr,
 
39
    'wchar':              xpt.Type.Tags.wchar_t,
 
40
    'wstring':            xpt.Type.Tags.wchar_t_ptr,
 
41
    # special types
 
42
    'nsid':               xpt.Type.Tags.nsIID,
 
43
    'domstring':          xpt.Type.Tags.DOMString,
 
44
    'astring':            xpt.Type.Tags.AString,
 
45
    'utf8string':         xpt.Type.Tags.UTF8String,
 
46
    'cstring':            xpt.Type.Tags.CString,
 
47
    'jsval':              xpt.Type.Tags.jsval
 
48
}
 
49
 
 
50
# XXXkhuey dipper types should go away (bug 677784)
 
51
def isDipperType(type):
 
52
    return type == xpt.Type.Tags.DOMString or type == xpt.Type.Tags.AString or type == xpt.Type.Tags.CString or type == xpt.Type.Tags.UTF8String
 
53
 
 
54
def build_interface(iface, ifaces):
 
55
    def get_type(type, calltype, iid_is=None, size_is=None):
 
56
        """ Return the appropriate xpt.Type object for this param """
 
57
 
 
58
        while isinstance(type, xpidl.Typedef):
 
59
            type = type.realtype
 
60
 
 
61
        if isinstance(type, xpidl.Builtin):
 
62
            if type.name == 'string' and size_is != None:
 
63
                  return xpt.StringWithSizeType(size_is, size_is)
 
64
            elif type.name == 'wstring' and size_is != None:
 
65
                  return xpt.WideStringWithSizeType(size_is, size_is)
 
66
            else:
 
67
                  tag = TypeMap[type.name]
 
68
                  isPtr = (tag == xpt.Type.Tags.char_ptr or tag == xpt.Type.Tags.wchar_t_ptr)
 
69
                  return xpt.SimpleType(tag,
 
70
                                        pointer=isPtr,
 
71
                                        reference=False)
 
72
 
 
73
        if isinstance(type, xpidl.Array):
 
74
            # NB: For an Array<T> we pass down the iid_is to get the type of T.
 
75
            #     This allows Arrays of InterfaceIs types to work.
 
76
            return xpt.ArrayType(get_type(type.type, calltype, iid_is), size_is,
 
77
                                 #XXXkhuey length_is duplicates size_is (bug 677788),
 
78
                                 size_is)
 
79
 
 
80
        if isinstance(type, xpidl.Interface) or isinstance(type, xpidl.Forward):
 
81
            xptiface = None
 
82
            for i in ifaces:
 
83
                if i.name == type.name:
 
84
                    xptiface = i
 
85
 
 
86
            if not xptiface:
 
87
                xptiface = xpt.Interface(name=type.name)
 
88
                ifaces.append(xptiface)
 
89
 
 
90
            return xpt.InterfaceType(xptiface)
 
91
 
 
92
        if isinstance(type, xpidl.Native):
 
93
            if type.specialtype:
 
94
                # XXXkhuey jsval is marked differently in the typelib and in the headers :-(
 
95
                isPtr = (type.isPtr(calltype) or type.isRef(calltype)) and not type.specialtype == 'jsval'
 
96
                isRef = type.isRef(calltype) and not type.specialtype == 'jsval'
 
97
                return xpt.SimpleType(TypeMap[type.specialtype],
 
98
                                      pointer=isPtr,
 
99
                                      reference=isRef)
 
100
            elif iid_is != None:
 
101
                return xpt.InterfaceIsType(iid_is)
 
102
            else:
 
103
                # void ptr
 
104
                return xpt.SimpleType(TypeMap['void'],
 
105
                                      pointer=True,
 
106
                                      reference=False)
 
107
 
 
108
        raise Exception("Unknown type!")
 
109
 
 
110
    def get_nsresult():
 
111
        return xpt.SimpleType(TypeMap['nsresult'])
 
112
 
 
113
    def build_nsresult_param():
 
114
        return xpt.Param(get_nsresult())
 
115
 
 
116
    def get_result_type(m):
 
117
        if not m.notxpcom:
 
118
            return get_nsresult()
 
119
 
 
120
        return get_type(m.realtype, '')
 
121
 
 
122
    def build_result_param(m):
 
123
        return xpt.Param(get_result_type(m))
 
124
 
 
125
    def build_retval_param(m):
 
126
        type = get_type(m.realtype, 'out')
 
127
        if isDipperType(type.tag):
 
128
            # NB: The retval bit needs to be set here, contrary to what the
 
129
            # xpt spec says.
 
130
            return xpt.Param(type, in_=True, retval=True, dipper=True)
 
131
        return xpt.Param(type, in_=False, out=True, retval=True)
 
132
 
 
133
    def build_attr_param(a, getter=False, setter=False):
 
134
        if not (getter or setter):
 
135
            raise Exception("Attribute param must be for a getter or a setter!")
 
136
 
 
137
        type = get_type(a.realtype, getter and 'out' or 'in')
 
138
        if setter:
 
139
            return xpt.Param(type)
 
140
        else:
 
141
            if isDipperType(type.tag):
 
142
                # NB: The retval bit needs to be set here, contrary to what the
 
143
                # xpt spec says.
 
144
                return xpt.Param(type, in_=True, retval=True, dipper=True)
 
145
            return xpt.Param(type, in_=False, out=True, retval=True)
 
146
 
 
147
    if iface.namemap is None:
 
148
        raise Exception("Interface was not resolved.")
 
149
 
 
150
    consts = []
 
151
    methods = []
 
152
 
 
153
    def build_const(c):
 
154
        consts.append(xpt.Constant(c.name, get_type(c.basetype, ''), c.getValue()))
 
155
 
 
156
    def build_method(m):
 
157
        params = []
 
158
 
 
159
        def build_param(p):
 
160
            def findattr(p, attr):
 
161
                if hasattr(p, attr) and getattr(p, attr):
 
162
                    for i, param in enumerate(m.params):
 
163
                        if param.name == getattr(p, attr):
 
164
                            return i
 
165
                    return None
 
166
 
 
167
            iid_is = findattr(p, 'iid_is')
 
168
            size_is = findattr(p, 'size_is')
 
169
 
 
170
            in_ = p.paramtype.count("in")
 
171
            out = p.paramtype.count("out")
 
172
            dipper = False
 
173
            type = get_type(p.realtype, p.paramtype, iid_is=iid_is, size_is=size_is)
 
174
            if out and isDipperType(type.tag):
 
175
                out = False
 
176
                dipper = True
 
177
 
 
178
            return xpt.Param(type, in_, out, p.retval, p.shared, dipper, p.optional)
 
179
 
 
180
        for p in m.params:
 
181
            params.append(build_param(p))
 
182
 
 
183
        if not m.notxpcom and m.realtype.name != 'void':
 
184
            params.append(build_retval_param(m))
 
185
 
 
186
        methods.append(xpt.Method(m.name, build_result_param(m), params,
 
187
                                  getter=False, setter=False, notxpcom=m.notxpcom,
 
188
                                  constructor=False, hidden=m.noscript,
 
189
                                  optargc=m.optional_argc,
 
190
                                  implicit_jscontext=m.implicit_jscontext))
 
191
 
 
192
    def build_attr(a):
 
193
        # Write the getter
 
194
        methods.append(xpt.Method(a.name, build_nsresult_param(),
 
195
                                  [build_attr_param(a, getter=True)],
 
196
                                  getter=True, setter=False, notxpcom=a.notxpcom,
 
197
                                  constructor=False, hidden=a.noscript,
 
198
                                  optargc=False,
 
199
                                  implicit_jscontext=a.implicit_jscontext))
 
200
 
 
201
        # And maybe the setter
 
202
        if not a.readonly:
 
203
            methods.append(xpt.Method(a.name, build_nsresult_param(),
 
204
                                      [build_attr_param(a, setter=True)],
 
205
                                      getter=False, setter=True, notxpcom=a.notxpcom,
 
206
                                      constructor=False, hidden=a.noscript,
 
207
                                      optargc=False,
 
208
                                      implicit_jscontext=a.implicit_jscontext))
 
209
 
 
210
    for member in iface.members:
 
211
        if isinstance(member, xpidl.ConstMember):
 
212
            build_const(member)
 
213
        elif isinstance(member, xpidl.Attribute):
 
214
            build_attr(member)
 
215
        elif isinstance(member, xpidl.Method):
 
216
            build_method(member)
 
217
        elif isinstance(member, xpidl.CDATA):
 
218
            pass
 
219
        else:
 
220
            raise Exception("Unexpected interface member: %s" % member)
 
221
 
 
222
    parent = None
 
223
    if iface.base:
 
224
        for i in ifaces:
 
225
            if i.name == iface.base:
 
226
                parent = i
 
227
        if not parent:
 
228
            parent = xpt.Interface(name=iface.base)
 
229
            ifaces.append(parent)
 
230
 
 
231
    return xpt.Interface(iface.name, iface.attributes.uuid, methods=methods,
 
232
                         constants=consts, resolved=True, parent=parent,
 
233
                         scriptable=iface.attributes.scriptable,
 
234
                         function=iface.attributes.function,
 
235
                         builtinclass=iface.attributes.builtinclass)
 
236
 
 
237
def write_typelib(idl, fd, filename):
 
238
    """ Generate the typelib. """
 
239
 
 
240
    # We only care about interfaces
 
241
    ifaces = []
 
242
    for p in idl.productions:
 
243
        if p.kind == 'interface':
 
244
            ifaces.append(build_interface(p, ifaces))
 
245
 
 
246
    typelib = xpt.Typelib(interfaces=ifaces)
 
247
    typelib.writefd(fd)
 
248
 
 
249
if __name__ == '__main__':
 
250
    from optparse import OptionParser
 
251
    o = OptionParser()
 
252
    o.add_option('-I', action='append', dest='incdirs', default=['.'],
 
253
                 help="Directory to search for imported files")
 
254
    o.add_option('--cachedir', dest='cachedir', default=None,
 
255
                 help="Directory in which to cache lex/parse tables.")
 
256
    o.add_option('-o', dest='outfile', default=None,
 
257
                 help="Output file")
 
258
    o.add_option('-d', dest='depfile', default=None,
 
259
                 help="Generate a make dependency file")
 
260
    o.add_option('--regen', action='store_true', dest='regen', default=False,
 
261
                 help="Regenerate IDL Parser cache")
 
262
    options, args = o.parse_args()
 
263
    file = args[0] if args else None
 
264
 
 
265
    if options.cachedir is not None:
 
266
        if not os.path.isdir(options.cachedir):
 
267
            os.mkdir(options.cachedir)
 
268
        sys.path.append(options.cachedir)
 
269
 
 
270
    if options.regen:
 
271
        if options.cachedir is None:
 
272
            print >>sys.stderr, "--regen requires --cachedir"
 
273
            sys.exit(1)
 
274
 
 
275
        p = xpidl.IDLParser(outputdir=options.cachedir, regen=True)
 
276
        sys.exit(0)
 
277
 
 
278
    if options.depfile is not None and options.outfile is None:
 
279
        print >>sys.stderr, "-d requires -o"
 
280
        sys.exit(1)
 
281
 
 
282
    if options.outfile is not None:
 
283
        outfd = open(options.outfile, 'wb')
 
284
        closeoutfd = True
 
285
    else:
 
286
        raise "typelib generation requires an output file"
 
287
 
 
288
    p = xpidl.IDLParser(outputdir=options.cachedir)
 
289
    idl = p.parse(open(file).read(), filename=file)
 
290
    idl.resolve(options.incdirs, p)
 
291
    write_typelib(idl, outfd, file)
 
292
 
 
293
    if closeoutfd:
 
294
        outfd.close()
 
295
 
 
296
    if options.depfile is not None:
 
297
        depfd = open(options.depfile, 'w')
 
298
        deps = [dep.replace('\\', '/') for dep in idl.deps]
 
299
 
 
300
        print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))