#!/usr/bin/env python # header.py - Generate C++ header 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/.
"""Print a C++ header file for the IDL files specified on the command line"""
import itertools import os.path import re
from xpidl import xpidl
printdoccomments = False
if printdoccomments:
def printComments(fd, clist, indent): for c in clist:
fd.write("%s%s\n" % (indent, c))
def attributeParamNames(a, getter, return_param=True): if getter and (a.notxpcom ornot return_param):
l = [] else:
l = [attributeParamName(a)] if a.implicit_jscontext:
l.insert(0, "cx") return", ".join(l)
# Ideally, we'd set MOZ_CAN_RUN_SCRIPT in the "scriptable and not # builtinclass" case too, so we'd just have memberCanRunScript() check # explicit_setter_can_run_script/explicit_setter_can_run_script and call it # here. But that would likely require a fair amount of Gecko-side # annotation work. See bug 1534292. if (a.explicit_getter_can_run_script and getter) or (
a.explicit_setter_can_run_script andnot getter
):
ret = "MOZ_CAN_RUN_SCRIPT " + ret
return ret
def attributeReturnType(a, getter, macro): """macro should be NS_IMETHOD or NS_IMETHODIMP""" # Pick the type to be returned from the getter/setter. if a.notxpcom:
ret = a.realtype.nativeType("in").strip() if getter else"void" else:
ret = "nsresult"
# Set calling convention and virtual-ness if a.nostdcall: if macro == "NS_IMETHOD": # This is the declaration.
ret = "virtual %s" % ret else: if ret == "nsresult":
ret = macro else:
ret = "%s_(%s)" % (macro, ret)
return attributeAttributes(a, getter) + ret
def attributeParamlist(a, getter, return_param=True): if getter and (a.notxpcom ornot return_param):
l = [] else:
l = [ "%s%s"
% (a.realtype.nativeType(getter and"out"or"in"), attributeParamName(a))
] if a.implicit_jscontext:
l.insert(0, "JSContext* cx")
def methodNativeName(m): return m.binaryname isnotNoneand m.binaryname or firstCap(m.name)
def methodAttributes(m):
ret = ""
if m.must_use:
ret = "[[nodiscard]] " + ret
# Ideally, we'd set MOZ_CAN_RUN_SCRIPT in the "scriptable and not # builtinclass" case too, so we'd just have memberCanRunScript() check # explicit_can_run_script and call it here. But that would likely require # a fair amount of Gecko-side annotation work. See bug 1534292. if m.explicit_can_run_script:
ret = "MOZ_CAN_RUN_SCRIPT " + ret
return ret
def methodReturnType(m, macro): """macro should be NS_IMETHOD or NS_IMETHODIMP""" if m.notxpcom:
ret = m.realtype.nativeType("in").strip() else:
ret = "nsresult"
# Set calling convention and virtual-ness if m.nostdcall: if macro == "NS_IMETHOD": # This is the declaration
ret = "virtual %s" % ret else: if ret == "nsresult":
ret = macro else:
ret = "%s_(%s)" % (macro, ret)
# Set any optional out params to default to nullptr. Skip if we just added # extra non-optional args to l. if len(l) == len(m.params):
paramIter = len(m.params) - 1 while (
paramIter >= 0 and m.params[paramIter].optional and"out"in m.params[paramIter].paramtype
):
t = m.params[paramIter].type # Strings can't be optional, so this shouldn't happen, but let's make sure: if t == "AString"or t == "ACString"or t == "AUTF8String": break
l[paramIter] += " = nullptr"
paramIter -= 1
if len(l) == 0: return empty
return", ".join(l)
def memberCanRunScript(member): # This can only happen if the member is scriptable and its interface is not builtinclass. return member.isScriptable() andnot member.iface.attributes.builtinclass
foundinc = False for inc in idl.includes(): ifnot foundinc:
foundinc = True
fd.write("\n")
fd.write(include % {"basename": idl_basename(inc.filename)})
if idl.needsJSTypes():
fd.write(jsvalue_include)
# Include some extra files if any attributes are infallible.
interfaces = [p for p in idl.productions if p.kind == "interface"]
wroteRunScriptIncludes = False
wroteInfallibleIncludes = False for iface in interfaces: for member in iface.members: ifnot isinstance(member, xpidl.Attribute) andnot isinstance(
member, xpidl.Method
): continue ifnot wroteInfallibleIncludes and member.infallible:
fd.write(infallible_includes)
wroteInfallibleIncludes = True ifnot wroteRunScriptIncludes and memberCanRunScript(member):
fd.write(can_run_script_includes)
wroteRunScriptIncludes = True if wroteRunScriptIncludes and wroteInfallibleIncludes: break
fd.write("\n")
fd.write(header_end)
for p in idl.productions: if p.kind == "include": continue if p.kind == "cdata":
fd.write(p.data) continue
if p.kind == "webidl":
write_webidl(p, fd) continue if p.kind == "forward":
fd.write(forward_decl % {"name": p.name}) continue if p.kind == "interface":
write_interface(p, fd) continue if p.kind == "typedef":
printComments(fd, p.doccomments, "")
fd.write("typedef %s %s;\n\n" % (p.realtype.nativeType("in"), p.name))
/* Use this macro when declaring classes that implement this interface. */ #define NS_DECL_%(macroname)s """
iface_nonvirtual = """
/* Use this macro when declaring the members of this interface when the class doesn't implement the interface. This is useful for forwarding. */ #define NS_DECL_NON_VIRTUAL_%(macroname)s """
iface_forward = """
/* Use this macro to declare functions that forward the behavior of this interface to another object. */ #define NS_FORWARD_%(macroname)s(_to) """ # NOQA: E501
iface_forward_safe = """
/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ #define NS_FORWARD_SAFE_%(macroname)s(_to) """ # NOQA: E501
# NOTE: We don't use RefPtr::forget here because we don't want to need the # definition of %(realtype)s in scope, which we would need for the # AddRef/Release calls.
refcnt_infallible_tmpl = """\
%(attributes)s inline already_AddRefed<%(realtype)s> %(nativename)s(%(args)s)
{
%(realtype)s* result = nullptr;
mozilla::DebugOnly<nsresult> rv = %(nativename)s(%(argnames)s&result);
MOZ_ASSERT(NS_SUCCEEDED(rv)); return already_AddRefed<%(realtype)s>(result);
} """
iface_threadsafe_tmpl = """\
namespace mozilla::detail {
template <> class InterfaceNeedsThreadSafeRefCnt<%(name)s> : public std::true_type {};
} """
def write_interface(iface, fd): if iface.namemap isNone: raise Exception("Interface was not resolved.")
# Confirm that no names of methods will overload in this interface
names = set()
def record_name(name): if name in names: raise Exception( "Unexpected overloaded virtual method %s in interface %s"
% (name, iface.name)
)
names.add(name)
for m in iface.members: if type(m) is xpidl.Attribute:
record_name(attributeNativeName(m, getter=True)) ifnot m.readonly:
record_name(attributeNativeName(m, getter=False)) elif type(m) is xpidl.Method:
record_name(methodNativeName(m))
fd.write("class ")
foundcdata = False for m in iface.members: if isinstance(m, xpidl.CDATA):
foundcdata = True
ifnot foundcdata:
fd.write("NS_NO_VTABLE ")
fd.write(iface.name) if iface.base:
fd.write(" : public %s" % iface.base)
fd.write(iface_prolog % names)
if iface.attributes.scriptable:
fd.write(iface_scriptable % names)
for key, group in itertools.groupby(iface.members, key=type): if key == xpidl.ConstMember:
write_const_decls(group) # iterator of all the consts else: for member in group: if key == xpidl.Attribute:
write_attr_decl(member) elif key == xpidl.Method:
write_method_decl(member) elif key == xpidl.CDATA:
fd.write(" %s" % member.data) elif key == xpidl.CEnum:
write_cenum_decl(member) else: raise Exception("Unexpected interface member: %s" % member)
fd.write(iface_epilog % names)
if iface.attributes.rust_sync:
fd.write(iface_threadsafe_tmpl % names)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.