Bug 648801 (new DOM list bindings) - Generate setters on new DOM bindings. r=bz/jst/mrbkap.
authorPeter Van der Beken <peterv@propagandism.org>
Sat, 20 Aug 2011 15:53:33 +0200
changeset 79800 7b0e7af95fcbca28dbc2231c0f4a6fea51a9434e
parent 79799 669ec5b8b282cdd44e2c871e9f4b5c23b1918ab9
child 79801 5d583adcbde6b0e2ceff399ad68b88dd62baebad
push id434
push userclegnitto@mozilla.com
push dateWed, 21 Dec 2011 12:10:54 +0000
treeherdermozilla-beta@bddb6ed8dd47 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, jst, mrbkap
bugs648801
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 648801 (new DOM list bindings) - Generate setters on new DOM bindings. r=bz/jst/mrbkap.
js/src/xpconnect/src/dombindingsgen.py
xpcom/idl-parser/xpidl.py
--- a/js/src/xpconnect/src/dombindingsgen.py
+++ b/js/src/xpconnect/src/dombindingsgen.py
@@ -88,17 +88,19 @@ def firstCap(str):
 
 class DOMClass(UserDict.DictMixin):
     def __init__(self, name, nativeClass):
         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()
 
     @staticmethod
     def getterNativeType(getter):
         if isStringType(getter.realtype):
             return 'nsString'
         type = getter.realtype
@@ -128,57 +130,91 @@ class DOMClass(UserDict.DictMixin):
                     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(nsnull, 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)
 
-        def ops(getterType):
+        if key == 'nameSet':
+            return DOMClass.setterNativeCall(self.realNameSetter)
+
+        def ops(getterType, setterType):
             def opType(type):
                 return type + (" " if type.endswith('>') else "")
 
-            if getterType:
+            if getterType or setterType:
                 opsClass = ", Ops<"
-                opsClass += "Getter<" + opType(getterType) + ">"
+                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)
+            return ops(self.indexGetter and self.indexGetterType, self.indexSetter and self.indexSetterType)
         if key == 'nameOps':
-            return ops(self.nameGetter and self.nameGetterType) if self.nameGetter else ""
+            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)
 
@@ -250,18 +286,22 @@ def completeConfiguration(conf, includeP
                 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')
@@ -289,16 +329,18 @@ def getTypes(classes, map={}):
     def getTranslatedType(type):
         return map.get(type, type)
 
     types = set()
     for clazz in classes.itervalues():
         types.add(getTranslatedType(clazz.nativeClass))
         if clazz.indexGetter and needsForwardDeclaration(clazz.realIndexGetter.realtype):
             types.add(getTranslatedType(clazz.realIndexGetter.realtype.name))
+        if clazz.indexSetter and needsForwardDeclaration(clazz.realIndexSetter.realtype):
+            types.add(getTranslatedType(clazz.realIndexSetter.realtype.name))
         if clazz.nameGetter and needsForwardDeclaration(clazz.realNameGetter.realtype):
             types.add(getTranslatedType(clazz.realNameGetter.realtype.name))
     return sorted(types)
 
 listDefinitionTemplate = (
 "class ${name} {\n"
 "public:\n"
 "    template<typename I>\n"
@@ -453,25 +495,43 @@ indexGetterTemplate = (
 "template<>\n"
 "bool\n"
 "${name}Wrapper::getItemAt(${nativeClass} *list, uint32 index, ${indexGetterType} &item)\n"
 "{\n"
 "${indexGet}"
 "}\n"
 "\n")
 
+indexSetterTemplate = (
+"template<>\n"
+"bool\n"
+"${name}Wrapper::setItemAt(${nativeClass} *list, uint32 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(${nativeClass} *list, const nsAString& index, ${nameSetterType} item)\n"
+"{\n"
+"${nameSet}"
+"}\n"
+"\n")
+
 listTemplateFooter = (
 "template<>\n"
 "${name}Wrapper::Properties ${name}Wrapper::sProtoProperties[] = {\n"
 "${properties}\n"
 "};\n"
 "\n""template<>\n"
 "${name}Wrapper::Methods ${name}Wrapper::sProtoMethods[] = {\n"
 "${methods}\n"
@@ -576,16 +636,18 @@ def writeStubFile(filename, config, inte
                 "namespace binding {\n\n")
 
         f.write("// Property name ids\n\n")
 
         ids = set()
         for clazz in config.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)
 
@@ -622,19 +684,23 @@ def writeStubFile(filename, config, inte
             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 clazz.members:
                 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"
 
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -500,21 +500,23 @@ class Interface(object):
 
         for m in members:
             if not isinstance(m, CDATA):
                 self.namemap.set(m)
 
         self.ops = {
             'index':
                 {
-                    'getter': None
+                    'getter': None,
+                    'setter': None
                 },
             'name':
                 {
-                    'getter': None
+                    'getter': None,
+                    'setter': None
                 },
             'stringifier': None
             }
 
     def __eq__(self, other):
         return self.name == other.name and self.location == other.location
 
     def resolve(self, parent):
@@ -811,16 +813,17 @@ class Method(object):
     noscript = False
     notxpcom = False
     binaryname = None
     implicit_jscontext = False
     nostdcall = False
     optional_argc = False
     deprecated = False
     getter = False
+    setter = False
     stringifier = False
     forward = None
 
     def __init__(self, type, name, attlist, paramlist, location, doccomments, raises):
         self.type = type
         self.name = name
         self.attlist = attlist
         self.params = paramlist
@@ -858,16 +861,20 @@ class Method(object):
             elif name == 'deprecated':
                 self.deprecated = True
             elif name == 'nostdcall':
                 self.nostdcall = True
             elif name == 'getter':
                 if (len(self.params) != 1):
                     raise IDLError("Methods marked as getter must take 1 argument", aloc)
                 self.getter = True
+            elif name == 'setter':
+                if (len(self.params) != 2):
+                    raise IDLError("Methods marked as setter must take 2 arguments", aloc)
+                self.setter = True
             elif name == 'stringifier':
                 if (len(self.params) != 0):
                     raise IDLError("Methods marked as stringifier must take 0 arguments", aloc)
                 self.stringifier = True
             else:
                 raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
         self.namemap = NameMap()
@@ -884,16 +891,27 @@ class Method(object):
                 ops = 'index'
             else:
                 if getBuiltinOrNativeTypeName(self.params[0].realtype) != '[domstring]':
                     raise IDLError("a getter must take a single unsigned long or DOMString argument" % self.iface.name, self.location)
                 ops = 'name'
             if self.iface.ops[ops]['getter']:
                 raise IDLError("a %s getter was already defined on interface '%s'" % (ops, self.iface.name), self.location)
             self.iface.ops[ops]['getter'] = self
+        if self.setter:
+            if getBuiltinOrNativeTypeName(self.params[0].realtype) == 'unsigned long':
+                ops = 'index'
+            else:
+                if getBuiltinOrNativeTypeName(self.params[0].realtype) != '[domstring]':
+                    print getBuiltinOrNativeTypeName(self.params[0].realtype)
+                    raise IDLError("a setter must take a unsigned long or DOMString argument" % self.iface.name, self.location)
+                ops = 'name'
+            if self.iface.ops[ops]['setter']:
+                raise IDLError("a %s setter was already defined on interface '%s'" % (ops, self.iface.name), self.location)
+            self.iface.ops[ops]['setter'] = self
         if self.stringifier:
             if self.iface.ops['stringifier']:
                 raise IDLError("a stringifier was already defined on interface '%s'" % self.iface.name, self.location)
             if getBuiltinOrNativeTypeName(self.realtype) != '[domstring]':
                 raise IDLError("'stringifier' attribute can only be used on methods returning DOMString",
                                self.location)
             self.iface.ops['stringifier'] = self