https://github.com/mozilla/gecko-dev
Tip revision: 1b2df193b616a5c17614109e5fe2a121845aabd2 authored by ffxbld on 24 June 2012, 08:11:04 UTC
Added FIREFOX_14_0b9_RELEASE FIREFOX_14_0b9_BUILD1 tag(s) for changeset d050090e578c. DONTBUILD CLOSED TREE a=release
Added FIREFOX_14_0b9_RELEASE FIREFOX_14_0b9_BUILD1 tag(s) for changeset d050090e578c. DONTBUILD CLOSED TREE a=release
Tip revision: 1b2df19
dombindingsgen.py
#!/usr/bin/env/python
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
from codegen import *
import xpidl
import os, re
import string
import UserDict
# === Preliminaries
# --makedepend-output support.
make_dependencies = []
make_targets = []
# === Reading the file
def addStubMember(memberId, member):
# Add this member to the list.
member.iface.stubMembers.append(member)
def checkStubMember(member):
memberId = member.iface.name + "." + member.name
if member.kind not in ('method', 'attribute'):
raise UserError("Member %s is %r, not a method or attribute."
% (memberId, member.kind))
if member.noscript:
raise UserError("%s %s is noscript."
% (member.kind.capitalize(), memberId))
if member.notxpcom:
raise UserError(
"%s %s: notxpcom methods are not supported."
% (member.kind.capitalize(), memberId))
# Check for unknown properties.
for attrname, value in vars(member).items():
if value is True and attrname not in ('readonly','optional_argc',
'implicit_jscontext','getter',
'stringifier'):
raise UserError("%s %s: unrecognized property %r"
% (member.kind.capitalize(), memberId,
attrname))
def loadIDL(parser, includePath, filename):
make_dependencies.append(filename)
text = open(filename, 'r').read()
idl = parser.parse(text, filename=filename)
idl.resolve(includePath, parser)
return idl
def firstCap(str):
return str[0].upper() + str[1:]
class DOMClass(UserDict.DictMixin):
def __init__(self, name, nativeClass, prefable):
self.name = name
self.base = None
self.isBase = False
self.nativeClass = nativeClass
self.indexGetter = None
self.indexSetter = None
self.nameGetter = None
self.nameSetter = None
self.stringifier = False
self.members = set()
self.prefable = prefable
@staticmethod
def getterNativeType(getter):
if isStringType(getter.realtype):
return 'nsString'
type = getter.realtype
if type.kind in ('interface', 'forward'):
if not getter.notxpcom:
return "nsCOMPtr<%s>" % type.name
if len(getter.params) > 1:
assert len(getter.params) == 2
assert getter.params[1].realtype.kind == 'native' and getter.params[1].realtype.nativename == 'nsWrapperCache'
return 'nsISupportsResult'
return type.nativeType('in').strip()
@staticmethod
def getterNativeCall(getter):
if isStringType(getter.realtype):
template = (" list->%s(index, item);\n"
" return !DOMStringIsNull(item);\n")
else:
type = getter.realtype
if type.kind in ('interface', 'forward'):
if not getter.notxpcom:
template = " return NS_SUCCEEDED(list->%s(index, getter_AddRefs(item)));\n"
elif len(getter.params) > 1:
template = (" item.mResult = list->%s(index, &item.mCache);\n"
" return !!item.mResult;\n")
else:
template = (" item = list->%s(index);\n"
" return !!item;\n")
else:
template = (" item = list->%s(index);\n"
" return !!item;\n")
return template % header.methodNativeName(getter)
@staticmethod
def setterNativeCall(setter):
if setter.notxpcom:
template = (" !; // TODO")
else:
template = (" nsresult rv = list->%s(index, item);\n"
" return NS_SUCCEEDED(rv) ? true : Throw(cx, rv);\n")
return template % header.methodNativeName(setter)
def __setattr__(self, name, value):
self.__dict__[name] = value
if value:
if name == 'indexGetter':
if value.forward:
self.realIndexGetter = value.iface.namemap[value.forward]
else:
self.realIndexGetter = value
self.indexGetterType = self.getterNativeType(self.realIndexGetter)
elif name == 'indexSetter':
if value.forward:
self.realIndexSetter = value.iface.namemap[value.forward]
else:
self.realIndexSetter = value
self.indexSetterType = self.realIndexSetter.params[1].realtype.nativeType("in")
elif name == 'nameGetter':
if value.forward:
self.realNameGetter = value.iface.namemap[value.forward]
else:
self.realNameGetter = value
self.nameGetterType = self.getterNativeType(self.realNameGetter)
elif name == 'nameSetter':
if value.forward:
self.realNameSetter = value.iface.namemap[value.forward]
else:
self.realNameSetter = value
self.nameSetterType = self.getterNativeType(self.realNameSetter)
def __getitem__(self, key):
assert type(key) == str
if key == 'indexGet':
return DOMClass.getterNativeCall(self.realIndexGetter)
if key == 'indexSet':
return DOMClass.setterNativeCall(self.realIndexSetter)
if key == 'nameGet':
return DOMClass.getterNativeCall(self.realNameGetter)
if key == 'nameSet':
return DOMClass.setterNativeCall(self.realNameSetter)
def ops(getterType, setterType):
def opType(type):
return type + (" " if type.endswith('>') else "")
if getterType or setterType:
opsClass = ", Ops<"
if getterType:
opsClass += "Getter<" + opType(getterType) + ">"
else:
# Should we even support this?
opsClass += "NoOp"
if setterType:
opsClass += ", Setter<" + opType(setterType) + ">"
opsClass += " >"
else:
opsClass = ", NoOps"
return opsClass
if key == 'indexOps':
return ops(self.indexGetter and self.indexGetterType, self.indexSetter and self.indexSetterType)
if key == 'nameOps':
return ops(self.nameGetter and self.nameGetterType, self.nameSetter and self.nameSetterType) if self.nameGetter else ""
if key == 'listClass':
if self.base:
template = "DerivedListClass<${nativeClass}, ${base}Wrapper${indexOps}${nameOps} >"
else:
template = "ListClass<${nativeClass}${indexOps}${nameOps} >"
return string.Template(template).substitute(self)
return self.__dict__[key]
def __cmp__(x, y):
if x.isBase != y.isBase:
return -1 if x.isBase else 1
return cmp(x.name, y.name)
class Configuration:
def __init__(self, filename, includePath):
self.includePath = includePath
config = {}
execfile(filename, config)
# required settings
if 'list_classes' not in config:
raise UserError(filename + ": `%s` was not defined." % name)
if 'list_classes' not in config:
raise UserError(filename + ": `%s` was not defined." % name)
self.list_classes = {}
for clazz in config['list_classes']:
self.list_classes[clazz['name']] = \
DOMClass(name = clazz['name'],
nativeClass = clazz['nativeClass'],
prefable = False)
# optional settings
if 'prefableClasses' in config:
for clazz in config['prefableClasses']:
self.list_classes[clazz] = DOMClass(name=clazz, nativeClass=config['prefableClasses'][clazz], prefable=True)
self.customInheritance = config.get('customInheritance', {})
self.derivedClasses = {}
self.irregularFilenames = config.get('irregularFilenames', {})
self.customIncludes = config.get('customIncludes', [])
def readConfigFile(filename, includePath):
# Read the config file.
return Configuration(filename, includePath)
def completeConfiguration(conf, includePath, cachedir):
# Now read IDL files to connect the information in the config file to
# actual XPCOM interfaces, methods, and attributes.
interfaces = []
interfacesByName = {}
parser = xpidl.IDLParser(cachedir)
def getInterface(interfaceName, errorLoc):
iface = interfacesByName.get(interfaceName)
if iface is None:
idlFile = findIDL(conf.includePath, conf.irregularFilenames,
interfaceName)
idl = loadIDL(parser, conf.includePath, idlFile)
if not idl.hasName(interfaceName):
raise UserError("The interface %s was not found "
"in the idl file %r."
% (interfaceName, idlFile))
iface = idl.getName(interfaceName, errorLoc)
if not iface.attributes.scriptable:
raise UserError("Interface %s is not scriptable. "
"IDL file: %r." % (interfaceName, idlFile))
iface.stubMembers = []
interfaces.append(iface)
interfacesByName[interfaceName] = iface
return iface
stubbedInterfaces = []
for clazz in conf.list_classes.itervalues():
interfaceName = 'nsIDOM' + clazz.name
iface = getInterface(interfaceName, errorLoc='looking for %r' % clazz.name)
for member in iface.members:
if member.kind in ('method', 'attribute') and not member.noscript:
#addStubMember(iface.name + '.' + member.name, member)
clazz.members.add(member)
# Stub all scriptable members of this interface.
while True:
if iface not in stubbedInterfaces:
stubbedInterfaces.append(iface)
if not clazz.indexGetter and iface.ops['index']['getter']:
clazz.indexGetter = iface.ops['index']['getter']
if not clazz.indexSetter and iface.ops['index']['setter']:
clazz.indexSetter = iface.ops['index']['setter']
if not clazz.nameGetter and iface.ops['name']['getter']:
clazz.nameGetter = iface.ops['name']['getter']
if not clazz.nameSetter and iface.ops['name']['setter']:
clazz.nameSetter = iface.ops['name']['setter']
if not clazz.stringifier and iface.ops['stringifier']:
clazz.stringifier = iface.ops['stringifier']
interfaceName = conf.customInheritance.get(iface.name, iface.base)
iface = getInterface(interfaceName, errorLoc='looking for %r' % clazz.name)
if iface.name == 'nsISupports':
break
assert iface.name.startswith('nsIDOM') and not iface.name.startswith('nsIDOMNS')
clazz.base = iface.name[6:]
# For now we only support base classes that are real DOM
# list classes
assert clazz.base in conf.list_classes
if not conf.list_classes[clazz.base].isBase:
conf.list_classes[clazz.base].isBase = True
conf.derivedClasses[clazz.base] = []
conf.derivedClasses[clazz.base].append(clazz.name)
# Now go through and check all the interfaces' members
for iface in stubbedInterfaces:
for member in iface.stubMembers:
checkStubMember(member)
return interfaces
# === Generating the header file
def addType(types, type, map):
def getTranslatedType(type):
return map.get(type, type)
type = xpidl.unaliasType(type)
if isInterfaceType(type) or (type.kind == 'native' and type.specialtype is None):
types.add(getTranslatedType(type.name))
def getTypes(classes, map):
types = set()
for clazz in classes.itervalues():
types.add(map.get(clazz.nativeClass, clazz.nativeClass))
if clazz.indexGetter:
addType(types, clazz.realIndexGetter.realtype, map)
if clazz.indexSetter:
addType(types, clazz.realIndexSetter.realtype, map)
if clazz.nameGetter:
addType(types, clazz.realNameGetter.realtype, map)
if clazz.nameSetter:
addType(types, clazz.realNameSetter.realtype, map)
return types
listDefinitionTemplate = (
"class ${name} {\n"
"public:\n"
" template<typename I>\n"
" static JSObject *create(JSContext *cx, JSObject *scope, I *list, bool *triedToWrap)\n"
" {\n"
" return create(cx, scope, list, list, triedToWrap);\n"
" }\n"
"\n"
" static bool objIsWrapper(JSObject *obj);\n"
" static ${nativeClass} *getNative(JSObject *obj);\n"
"\n"
"private:\n"
" static JSObject *create(JSContext *cx, JSObject *scope, ${nativeClass} *list, nsWrapperCache *cache, bool *triedToWrap);\n"
"};"
"\n"
"\n")
def writeHeaderFile(filename, config):
print "Creating header file", filename
headerMacro = '__gen_%s__' % filename.replace('.', '_')
f = open(filename, 'w')
try:
f.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
"#ifndef " + headerMacro + "\n"
"#define " + headerMacro + "\n\n")
namespaces = []
for type in sorted(getTypes(config.list_classes, {})):
newNamespaces = type.split('::')
type = newNamespaces.pop()
j = 0
for i in range(min(len(namespaces), len(newNamespaces))):
if namespaces[i] != newNamespaces[i]:
break
j += 1
for i in range(j, len(namespaces)):
f.write("}\n")
namespaces.pop()
for i in range(j, len(newNamespaces)):
f.write("namespace %s {\n" % newNamespaces[i])
namespaces.append(newNamespaces[i])
f.write("class %s;\n" % type)
for namespace in namespaces:
f.write("}\n")
f.write("\n")
f.write("namespace mozilla {\n"
"namespace dom {\n"
"namespace binding {\n\n")
f.write("bool\n"
"DefinePropertyStaticJSVals(JSContext *cx);\n\n")
for clazz in config.list_classes.itervalues():
f.write(string.Template(listDefinitionTemplate).substitute(clazz))
f.write("\n"
"}\n"
"}\n"
"}\n\n")
f.write("#endif\n")
finally:
f.close()
def writeMakeDependOutput(filename):
print "Creating makedepend file", filename
f = open(filename, 'w')
try:
if len(make_targets) > 0:
f.write("%s:" % makeQuote(make_targets[0]))
for filename in make_dependencies:
f.write(' \\\n\t\t%s' % makeQuote(filename))
f.write('\n\n')
for filename in make_targets[1:]:
f.write('%s: %s\n' % (makeQuote(filename), makeQuote(make_targets[0])))
finally:
f.close()
# === Generating the source file
listTemplateHeader = (
"// ${name}\n"
"\n"
"typedef ${listClass} ${name}Class;\n"
"typedef ListBase<${name}Class> ${name}Wrapper;\n"
"\n"
"\n")
listTemplate = (
"// ${name}\n"
"\n"
"template<>\n"
"js::Class ${name}Wrapper::sInterfaceClass = {\n"
" \"${name}\",\n"
" 0,\n"
" JS_PropertyStub, /* addProperty */\n"
" JS_PropertyStub, /* delProperty */\n"
" JS_PropertyStub, /* getProperty */\n"
" JS_StrictPropertyStub, /* setProperty */\n"
" JS_EnumerateStub,\n"
" JS_ResolveStub,\n"
" JS_ConvertStub,\n"
" NULL, /* finalize */\n"
" NULL, /* checkAccess */\n"
" NULL, /* call */\n"
" NULL, /* construct */\n"
" interface_hasInstance\n"
"};\n"
"\n")
derivedClassTemplate = (
"template<>\n"
"bool\n"
"${name}Wrapper::objIsList(JSObject *obj)\n"
"{\n"
" if (!js::IsProxy(obj))\n"
" return false;\n"
" js::ProxyHandler *handler = js::GetProxyHandler(obj);\n"
" return proxyHandlerIsList(handler) ||\n"
"${checkproxyhandlers};\n"
"}\n"
"\n"
"template<>\n"
"${nativeClass}*\n"
"${name}Wrapper::getNative(JSObject *obj)\n"
"{\n"
" js::ProxyHandler *handler = js::GetProxyHandler(obj);\n"
" if (proxyHandlerIsList(handler))\n"
" return static_cast<${nativeClass}*>(js::GetProxyPrivate(obj).toPrivate());\n"
"${castproxyhandlers}"
"\n"
" NS_RUNTIMEABORT(\"Unknown list type!\");\n"
" return NULL;\n"
"}\n"
"\n")
prefableClassTemplate = (
"template<>\n"
"JSObject *\n"
"${name}Wrapper::getPrototype(JSContext *cx, JSObject *receiver, bool *enabled)\n"
"{\n"
" XPCWrappedNativeScope *scope =\n"
" XPCWrappedNativeScope::FindInJSObjectScope(cx, receiver);\n"
" if (!scope)\n"
" return false;\n"
"\n"
" if (!scope->NewDOMBindingsEnabled()) {\n"
" *enabled = false;\n"
" return NULL;\n"
" }\n"
"\n"
" *enabled = true;\n"
" return getPrototype(cx, scope, receiver);\n"
"}\n"
"\n")
toStringTemplate = (
"template<>\n"
"JSString *\n"
"${name}Wrapper::obj_toString(JSContext *cx, JSObject *proxy)\n"
"{\n"
" nsString result;\n"
" nsresult rv = ${name}Wrapper::getListObject(proxy)->ToString(result);\n"
" JSString *jsresult;\n"
" return NS_SUCCEEDED(rv) && xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;\n"
"}\n"
"\n")
indexGetterTemplate = (
"template<>\n"
"bool\n"
"${name}Wrapper::getItemAt(${nativeClass} *list, uint32_t index, ${indexGetterType} &item)\n"
"{\n"
"${indexGet}"
"}\n"
"\n")
indexSetterTemplate = (
"template<>\n"
"bool\n"
"${name}Wrapper::setItemAt(JSContext *cx, ${nativeClass} *list, uint32_t index, ${indexSetterType} item)\n"
"{\n"
"${indexSet}"
"}\n"
"\n")
nameGetterTemplate = (
"template<>\n"
"bool\n"
"${name}Wrapper::getNamedItem(${nativeClass} *list, const nsAString& index, ${nameGetterType} &item)\n"
"{\n"
"${nameGet}"
"}\n"
"\n")
nameSetterTemplate = (
"template<>\n"
"bool\n"
"${name}Wrapper::setNamedItem(JSContext *cx, ${nativeClass} *list, const nsAString& index, ${nameSetterType} item)\n"
"{\n"
"${nameSet}"
"}\n"
"\n")
propertiesTemplate = (
"template<>\n"
"${name}Wrapper::Properties ${name}Wrapper::sProtoProperties[] = {\n"
"${properties}\n"
"};\n"
"\n"
"template<>\n"
"size_t ${name}Wrapper::sProtoPropertiesCount = ArrayLength(${name}Wrapper::sProtoProperties);\n"
"\n")
methodsTemplate = (
"template<>\n"
"${name}Wrapper::Methods ${name}Wrapper::sProtoMethods[] = {\n"
"${methods}\n"
"};\n"
"\n"
"template<>\n"
"size_t ${name}Wrapper::sProtoMethodsCount = ArrayLength(${name}Wrapper::sProtoMethods);\n"
"\n")
listTemplateFooter = (
"template class ListBase<${name}Class>;\n"
"\n"
"JSObject*\n"
"${name}::create(JSContext *cx, JSObject *scope, ${nativeClass} *list, nsWrapperCache *cache, bool *triedToWrap)\n"
"{\n"
" return ${name}Wrapper::create(cx, scope, list, cache, triedToWrap);\n"
"}\n"
"\n"
"bool\n"
"${name}::objIsWrapper(JSObject *obj)\n"
"{\n"
" return ${name}Wrapper::objIsList(obj);\n"
"}\n"
"\n"
"${nativeClass}*\n"
"${name}::getNative(JSObject *obj)\n"
"{\n"
" return ${name}Wrapper::getListObject(obj);\n"
"}\n"
"\n")
def writeBindingStub(f, classname, member, stubName, isSetter=False):
def writeThisUnwrapping(f, member, isMethod, isGetter, customMethodCall, haveCcx):
if isMethod:
f.write(" JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));\n"
" if (!%sWrapper::instanceIsListObject(cx, obj, callee))\n"
" return false;\n" % classname)
else:
f.write(" if (!%sWrapper::instanceIsListObject(cx, obj, NULL))\n"
" return false;\n" % classname)
return "%sWrapper::getListObject(obj)" % classname
def writeCheckForFailure(f, isMethod, isGeter, haveCcx):
f.write(" if (NS_FAILED(rv))\n"
" return xpc_qsThrowMethodFailedWithDetails(cx, rv, \"%s\", \"%s\");\n" % (classname, member.name))
def writeResultWrapping(f, member, jsvalPtr, jsvalRef):
if member.kind == 'method' and member.notxpcom and len(member.params) > 0 and member.params[len(member.params) - 1].paramtype == 'out':
assert member.params[len(member.params) - 1].realtype.kind == 'native' and member.params[len(member.params) - 1].realtype.nativename == 'nsWrapperCache'
template = " return Wrap(cx, obj, result, cache, ${jsvalPtr});\n"
else:
template = " return Wrap(cx, obj, result, ${jsvalPtr});\n"
writeResultConv(f, member.realtype, template, jsvalPtr, jsvalRef)
writeStub(f, {}, member, stubName, writeThisUnwrapping, writeCheckForFailure, writeResultWrapping, isSetter)
def writeAttrStubs(f, classname, attr):
getterName = classname + '_' + header.attributeNativeName(attr, True)
writeBindingStub(f, classname, attr, getterName)
if attr.readonly:
setterName = 'xpc_qsGetterOnlyPropertyStub'
else:
setterName = (classname + '_'
+ header.attributeNativeName(attr, False))
writeBindingStub(f, classname, attr, setterName, isSetter=True)
return " { s_%s_id, %s, %s }" % (attr.name, getterName, setterName)
def writeMethodStub(f, classname, method):
stubName = classname + '_' + header.methodNativeName(method)
writeBindingStub(f, classname, method, stubName)
return " { s_%s_id, %s, %i }" % (method.name, stubName, argumentsLength(method))
def writeStubFile(filename, config, interfaces):
print "Creating stub file", filename
make_targets.append(filename)
f = open(filename, 'w')
filesIncluded = set()
headerFilename = re.sub(r'(\.cpp)?$', '.h', filename)
try:
f.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n")
f.write("#include \"nsScriptNameSpaceManager.h\"\n")
types = getTypes(config.list_classes, config.irregularFilenames)
for clazz in config.list_classes.itervalues():
for member in clazz.members:
addType(types, member.realtype, config.irregularFilenames)
if member.kind == 'method':
for p in member.params:
addType(types, p.realtype, config.irregularFilenames)
f.write("".join([("#include \"%s.h\"\n" % re.sub(r'(([^:]+::)*)', '', type)) for type in sorted(types)]))
f.write("\n")
f.write("namespace mozilla {\n"
"namespace dom {\n"
"namespace binding {\n\n")
f.write("// Property name ids\n\n")
ids = set()
for clazz in config.list_classes.itervalues():
assert clazz.indexGetter
ids.add(clazz.indexGetter.name)
if clazz.indexSetter:
ids.add(clazz.indexSetter.name)
if clazz.nameGetter:
ids.add(clazz.nameGetter.name)
if clazz.stringifier:
ids.add('toString')
for member in clazz.members:
if member.name != 'length':
ids.add(member.name)
ids = sorted(ids)
for id in ids:
f.write("static jsid s_%s_id = JSID_VOID;\n" % id)
f.write("\n"
"bool\n"
"DefinePropertyStaticJSVals(JSContext *cx)\n"
"{\n")
f.write(" return %s;" % (" &&\n ".join([("SET_JSID_TO_STRING(cx, %s)" % id) for id in ids])))
f.write("\n"
"}\n\n")
classes = sorted(config.list_classes.values())
f.write("// Typedefs\n\n")
for clazz in classes:
f.write(string.Template(listTemplateHeader).substitute(clazz))
f.write("// Implementation\n\n")
for clazz in classes:
f.write(string.Template(listTemplate).substitute(clazz))
derivedClasses = config.derivedClasses.get(clazz.name, None)
if derivedClasses:
# If this hits we might need to do something better than just compare instance pointers
assert len(derivedClasses) <= 3
checkproxyhandlers = "||\n".join(map(lambda d: " %sWrapper::proxyHandlerIsList(handler)" % d, derivedClasses))
castproxyhandlers = "\n".join(map(lambda d: " if (%sWrapper::proxyHandlerIsList(handler))\n return %sWrapper::getNative(obj);\n" % (d, d), derivedClasses))
f.write(string.Template(derivedClassTemplate).substitute(clazz, checkproxyhandlers=checkproxyhandlers, castproxyhandlers=castproxyhandlers))
if clazz.prefable:
f.write(string.Template(prefableClassTemplate).substitute(clazz))
methodsList = []
propertiesList = []
if clazz.stringifier:
f.write(string.Template(toStringTemplate).substitute(clazz))
if clazz.stringifier.name != 'toString':
methodsList.append(" { s_toString_id, %s_%s, 0 }", clazz.name, header.methodNativeName(clazz.stringifier))
if clazz.indexGetter:
#methodsList.append(" { s_%s_id, &item, 1 }" % clazz.indexGetter.name)
f.write(string.Template(indexGetterTemplate).substitute(clazz))
if clazz.indexSetter:
f.write(string.Template(indexSetterTemplate).substitute(clazz))
if clazz.nameGetter:
#methodsList.append(" { s_%s_id, &namedItem, 1 }" % clazz.nameGetter.name)
f.write(string.Template(nameGetterTemplate).substitute(clazz))
if clazz.nameSetter:
f.write(string.Template(nameSetterTemplate).substitute(clazz))
for member in sorted(clazz.members, key=lambda member: member.name):
if member.name == 'length':
if not member.readonly:
setterName = (clazz.name + '_' + header.attributeNativeName(member, False))
writeBindingStub(f, clazz.name, member, setterName, isSetter=True)
else:
setterName = "NULL"
propertiesList.append(" { s_length_id, length_getter, %s }" % setterName)
continue
isAttr = (member.kind == 'attribute')
isMethod = (member.kind == 'method')
assert isAttr or isMethod
if isMethod:
methodsList.append(writeMethodStub(f, clazz.name, member))
else:
propertiesList.append(writeAttrStubs(f, clazz.name, member))
if len(propertiesList) > 0:
f.write(string.Template(propertiesTemplate).substitute(clazz, properties=",\n".join(propertiesList)))
if len(methodsList) > 0:
f.write(string.Template(methodsTemplate).substitute(clazz, methods=",\n".join(methodsList)))
f.write(string.Template(listTemplateFooter).substitute(clazz))
f.write("// Register prototypes\n\n")
f.write("void\n"
"Register(nsScriptNameSpaceManager* aNameSpaceManager)\n"
"{\n"
"#define REGISTER_PROTO(_dom_class) \\\n"
" aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), _dom_class##Wrapper::DefineDOMInterface);\n\n"""
"\n")
for clazz in config.list_classes.itervalues():
f.write(" REGISTER_PROTO(%s);\n" % clazz.name)
f.write("\n"
"#undef REGISTER_PROTO\n"
"}\n\n")
f.write("}\n"
"}\n"
"}\n")
finally:
f.close()
def main():
from optparse import OptionParser
o = OptionParser(usage="usage: %prog [options] configfile")
o.add_option('-o', "--stub-output",
type='string', dest='stub_output', default=None,
help="Quick stub C++ source output file", metavar="FILE")
o.add_option('--header-output', type='string', default=None,
help="Quick stub header output file", metavar="FILE")
o.add_option('--makedepend-output', type='string', default=None,
help="gnumake dependencies output file", metavar="FILE")
o.add_option('--idlpath', type='string', default='.',
help="colon-separated directories to search for idl files",
metavar="PATH")
o.add_option('--cachedir', dest='cachedir', default='',
help="Directory in which to cache lex/parse tables.")
o.add_option("--verbose-errors", action='store_true', default=False,
help="When an error happens, display the Python traceback.")
(options, filenames) = o.parse_args()
if len(filenames) != 1:
o.error("Exactly one config filename is needed.")
filename = filenames[0]
if options.cachedir != '':
sys.path.append(options.cachedir)
if not os.path.isdir(options.cachedir):
os.makedirs(options.cachedir)
try:
includePath = options.idlpath.split(':')
conf = readConfigFile(filename,
includePath=includePath)
if options.header_output is not None:
writeHeaderFile(options.header_output, conf)
elif options.stub_output is not None:
interfaces = completeConfiguration(conf,
includePath=includePath,
cachedir=options.cachedir)
writeStubFile(options.stub_output, conf, interfaces)
if options.makedepend_output is not None:
writeMakeDependOutput(options.makedepend_output)
except Exception, exc:
if options.verbose_errors:
raise
elif isinstance(exc, (UserError, xpidl.IDLError)):
warn(str(exc))
elif isinstance(exc, OSError):
warn("%s: %s" % (exc.__class__.__name__, exc))
else:
raise
sys.exit(1)
if __name__ == '__main__':
main()