summaryrefslogtreecommitdiff
path: root/xpcom/idl-parser/xpidl/typelib.py
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/idl-parser/xpidl/typelib.py')
-rw-r--r--xpcom/idl-parser/xpidl/typelib.py307
1 files changed, 307 insertions, 0 deletions
diff --git a/xpcom/idl-parser/xpidl/typelib.py b/xpcom/idl-parser/xpidl/typelib.py
new file mode 100644
index 0000000000..911e3873da
--- /dev/null
+++ b/xpcom/idl-parser/xpidl/typelib.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python
+# typelib.py - Generate XPCOM typelib files from IDL.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""Generate an XPIDL typelib for the IDL files specified on the command line"""
+
+import os
+import sys
+import xpidl
+import xpt
+
+# A map of xpidl.py types to xpt.py types
+TypeMap = {
+ # nsresult is not strictly an xpidl.py type, but it's useful here
+ 'nsresult': xpt.Type.Tags.uint32,
+ # builtins
+ 'boolean': xpt.Type.Tags.boolean,
+ 'void': xpt.Type.Tags.void,
+ 'int16_t': xpt.Type.Tags.int16,
+ 'int32_t': xpt.Type.Tags.int32,
+ 'int64_t': xpt.Type.Tags.int64,
+ 'uint8_t': xpt.Type.Tags.uint8,
+ 'uint16_t': xpt.Type.Tags.uint16,
+ 'uint32_t': xpt.Type.Tags.uint32,
+ 'uint64_t': xpt.Type.Tags.uint64,
+ 'octet': xpt.Type.Tags.uint8,
+ 'short': xpt.Type.Tags.int16,
+ 'long': xpt.Type.Tags.int32,
+ 'long long': xpt.Type.Tags.int64,
+ 'unsigned short': xpt.Type.Tags.uint16,
+ 'unsigned long': xpt.Type.Tags.uint32,
+ 'unsigned long long': xpt.Type.Tags.uint64,
+ 'float': xpt.Type.Tags.float,
+ 'double': xpt.Type.Tags.double,
+ 'char': xpt.Type.Tags.char,
+ 'string': xpt.Type.Tags.char_ptr,
+ 'wchar': xpt.Type.Tags.wchar_t,
+ 'wstring': xpt.Type.Tags.wchar_t_ptr,
+ # special types
+ 'nsid': xpt.Type.Tags.nsIID,
+ 'domstring': xpt.Type.Tags.DOMString,
+ 'astring': xpt.Type.Tags.AString,
+ 'utf8string': xpt.Type.Tags.UTF8String,
+ 'cstring': xpt.Type.Tags.CString,
+ 'jsval': xpt.Type.Tags.jsval
+}
+
+
+# XXXkhuey dipper types should go away (bug 677784)
+def isDipperType(type):
+ return type == xpt.Type.Tags.DOMString or type == xpt.Type.Tags.AString or type == xpt.Type.Tags.CString or type == xpt.Type.Tags.UTF8String
+
+
+def build_interface(iface, ifaces):
+ def get_type(type, calltype, iid_is=None, size_is=None):
+ """ Return the appropriate xpt.Type object for this param """
+
+ while isinstance(type, xpidl.Typedef):
+ type = type.realtype
+
+ if isinstance(type, xpidl.Builtin):
+ if type.name == 'string' and size_is is not None:
+ return xpt.StringWithSizeType(size_is, size_is)
+ elif type.name == 'wstring' and size_is is not None:
+ return xpt.WideStringWithSizeType(size_is, size_is)
+ else:
+ tag = TypeMap[type.name]
+ isPtr = (tag == xpt.Type.Tags.char_ptr or tag == xpt.Type.Tags.wchar_t_ptr)
+ return xpt.SimpleType(tag,
+ pointer=isPtr,
+ reference=False)
+
+ if isinstance(type, xpidl.Array):
+ # NB: For an Array<T> we pass down the iid_is to get the type of T.
+ # This allows Arrays of InterfaceIs types to work.
+ return xpt.ArrayType(get_type(type.type, calltype, iid_is), size_is,
+ #XXXkhuey length_is duplicates size_is (bug 677788),
+ size_is)
+
+ if isinstance(type, xpidl.Interface) or isinstance(type, xpidl.Forward):
+ xptiface = None
+ for i in ifaces:
+ if i.name == type.name:
+ xptiface = i
+
+ if not xptiface:
+ xptiface = xpt.Interface(name=type.name)
+ ifaces.append(xptiface)
+
+ return xpt.InterfaceType(xptiface)
+
+ if isinstance(type, xpidl.Native):
+ if type.specialtype:
+ # XXXkhuey jsval is marked differently in the typelib and in the headers :-(
+ isPtr = (type.isPtr(calltype) or type.isRef(calltype)) and not type.specialtype == 'jsval'
+ isRef = type.isRef(calltype) and not type.specialtype == 'jsval'
+ return xpt.SimpleType(TypeMap[type.specialtype],
+ pointer=isPtr,
+ reference=isRef)
+ elif iid_is is not None:
+ return xpt.InterfaceIsType(iid_is)
+ else:
+ # void ptr
+ return xpt.SimpleType(TypeMap['void'],
+ pointer=True,
+ reference=False)
+
+ raise Exception("Unknown type!")
+
+ def get_nsresult():
+ return xpt.SimpleType(TypeMap['nsresult'])
+
+ def build_nsresult_param():
+ return xpt.Param(get_nsresult())
+
+ def get_result_type(m):
+ if not m.notxpcom:
+ return get_nsresult()
+
+ return get_type(m.realtype, '')
+
+ def build_result_param(m):
+ return xpt.Param(get_result_type(m))
+
+ def build_retval_param(m):
+ type = get_type(m.realtype, 'out')
+ if isDipperType(type.tag):
+ # NB: The retval bit needs to be set here, contrary to what the
+ # xpt spec says.
+ return xpt.Param(type, in_=True, retval=True, dipper=True)
+ return xpt.Param(type, in_=False, out=True, retval=True)
+
+ def build_attr_param(a, getter=False, setter=False):
+ if not (getter or setter):
+ raise Exception("Attribute param must be for a getter or a setter!")
+
+ type = get_type(a.realtype, getter and 'out' or 'in')
+ if setter:
+ return xpt.Param(type)
+ else:
+ if isDipperType(type.tag):
+ # NB: The retval bit needs to be set here, contrary to what the
+ # xpt spec says.
+ return xpt.Param(type, in_=True, retval=True, dipper=True)
+ return xpt.Param(type, in_=False, out=True, retval=True)
+
+ if iface.namemap is None:
+ raise Exception("Interface was not resolved.")
+
+ consts = []
+ methods = []
+
+ def build_const(c):
+ consts.append(xpt.Constant(c.name, get_type(c.basetype, ''), c.getValue()))
+
+ def build_method(m):
+ params = []
+
+ def build_param(p):
+ def findattr(p, attr):
+ if hasattr(p, attr) and getattr(p, attr):
+ for i, param in enumerate(m.params):
+ if param.name == getattr(p, attr):
+ return i
+ return None
+
+ iid_is = findattr(p, 'iid_is')
+ size_is = findattr(p, 'size_is')
+
+ in_ = p.paramtype.count("in")
+ out = p.paramtype.count("out")
+ dipper = False
+ type = get_type(p.realtype, p.paramtype, iid_is=iid_is, size_is=size_is)
+ if out and isDipperType(type.tag):
+ out = False
+ dipper = True
+
+ return xpt.Param(type, in_, out, p.retval, p.shared, dipper, p.optional)
+
+ for p in m.params:
+ params.append(build_param(p))
+
+ if not m.notxpcom and m.realtype.name != 'void':
+ params.append(build_retval_param(m))
+
+ methods.append(xpt.Method(m.name, build_result_param(m), params,
+ getter=False, setter=False, notxpcom=m.notxpcom,
+ constructor=False, hidden=m.noscript,
+ optargc=m.optional_argc,
+ implicit_jscontext=m.implicit_jscontext))
+
+ def build_attr(a):
+ # Write the getter
+ methods.append(xpt.Method(a.name, build_nsresult_param(),
+ [build_attr_param(a, getter=True)],
+ getter=True, setter=False,
+ constructor=False, hidden=a.noscript,
+ optargc=False,
+ implicit_jscontext=a.implicit_jscontext))
+
+ # And maybe the setter
+ if not a.readonly:
+ methods.append(xpt.Method(a.name, build_nsresult_param(),
+ [build_attr_param(a, setter=True)],
+ getter=False, setter=True,
+ constructor=False, hidden=a.noscript,
+ optargc=False,
+ implicit_jscontext=a.implicit_jscontext))
+
+ for member in iface.members:
+ if isinstance(member, xpidl.ConstMember):
+ build_const(member)
+ elif isinstance(member, xpidl.Attribute):
+ build_attr(member)
+ elif isinstance(member, xpidl.Method):
+ build_method(member)
+ elif isinstance(member, xpidl.CDATA):
+ pass
+ else:
+ raise Exception("Unexpected interface member: %s" % member)
+
+ parent = None
+ if iface.base:
+ for i in ifaces:
+ if i.name == iface.base:
+ parent = i
+ if not parent:
+ parent = xpt.Interface(name=iface.base)
+ ifaces.append(parent)
+
+ return xpt.Interface(iface.name, iface.attributes.uuid, methods=methods,
+ constants=consts, resolved=True, parent=parent,
+ scriptable=iface.attributes.scriptable,
+ function=iface.attributes.function,
+ builtinclass=iface.attributes.builtinclass,
+ main_process_scriptable_only=iface.attributes.main_process_scriptable_only)
+
+
+def write_typelib(idl, fd, filename):
+ """ Generate the typelib. """
+
+ # We only care about interfaces that are scriptable.
+ ifaces = []
+ for p in idl.productions:
+ if p.kind == 'interface' and p.attributes.scriptable:
+ ifaces.append(build_interface(p, ifaces))
+
+ typelib = xpt.Typelib(interfaces=ifaces)
+ typelib.writefd(fd)
+
+if __name__ == '__main__':
+ from optparse import OptionParser
+ o = OptionParser()
+ o.add_option('-I', action='append', dest='incdirs', default=['.'],
+ help="Directory to search for imported files")
+ o.add_option('--cachedir', dest='cachedir', default=None,
+ help="Directory in which to cache lex/parse tables.")
+ o.add_option('-o', dest='outfile', default=None,
+ help="Output file")
+ o.add_option('-d', dest='depfile', default=None,
+ help="Generate a make dependency file")
+ o.add_option('--regen', action='store_true', dest='regen', default=False,
+ help="Regenerate IDL Parser cache")
+ options, args = o.parse_args()
+ file = args[0] if args else None
+
+ if options.cachedir is not None:
+ if not os.path.isdir(options.cachedir):
+ os.mkdir(options.cachedir)
+ sys.path.append(options.cachedir)
+
+ if options.regen:
+ if options.cachedir is None:
+ print >>sys.stderr, "--regen requires --cachedir"
+ sys.exit(1)
+
+ p = xpidl.IDLParser(outputdir=options.cachedir, regen=True)
+ sys.exit(0)
+
+ if options.depfile is not None and options.outfile is None:
+ print >>sys.stderr, "-d requires -o"
+ sys.exit(1)
+
+ if options.outfile is not None:
+ outfd = open(options.outfile, 'wb')
+ closeoutfd = True
+ else:
+ raise "typelib generation requires an output file"
+
+ p = xpidl.IDLParser(outputdir=options.cachedir)
+ idl = p.parse(open(file).read(), filename=file)
+ idl.resolve(options.incdirs, p)
+ write_typelib(idl, outfd, file)
+
+ if closeoutfd:
+ outfd.close()
+
+ if options.depfile is not None:
+ depfd = open(options.depfile, 'w')
+ deps = [dep.replace('\\', '/') for dep in idl.deps]
+
+ print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))
+ for dep in deps:
+ print >>depfd, "%s:" % dep