Bug 661984: Add [nostdcall] as an extended idl attribute. r=bsmedberg
authorJonas Sicking <jonas@sicking.cc>
Thu, 23 Jun 2011 19:17:58 -0700
changeset 71885 cfea84e7fd7c852e4b1b09b10eed0dded95e7bfd
parent 71884 c8f01a0d54822877edac39b04392c64d2e2c977d
child 71886 3fa43a74a6d9b593811617b04bd80666d60ddf2a
push idunknown
push userunknown
push dateunknown
reviewersbsmedberg
bugs661984
milestone7.0a1
Bug 661984: Add [nostdcall] as an extended idl attribute. r=bsmedberg
xpcom/idl-parser/header.py
xpcom/idl-parser/xpidl.py
xpcom/typelib/xpidl/xpidl_header.c
xpcom/typelib/xpidl/xpidl_util.c
--- a/xpcom/idl-parser/header.py
+++ b/xpcom/idl-parser/header.py
@@ -57,33 +57,46 @@ def firstCap(str):
 
 def attributeParamName(a):
     return "a" + firstCap(a.name)
 
 def attributeNativeName(a, getter):
     binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
     return "%s%s" % (getter and 'Get' or 'Set', binaryname)
 
+def attributeReturnType(a, macro):
+    """macro should be NS_IMETHOD or NS_IMETHODIMP"""
+    if (a.nostdcall):
+        return macro == "NS_IMETHOD" and "virtual nsresult" or "nsresult"
+    else:
+        return macro
+
 def attributeParamlist(a, getter):
     return "%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
                      attributeParamName(a))
 
 def attributeAsNative(a, getter):
         scriptable = a.isScriptable() and "NS_SCRIPTABLE " or ""
         params = {'scriptable': scriptable,
+                  'returntype': attributeReturnType(a, 'NS_IMETHOD'),
                   'binaryname': attributeNativeName(a, getter),
                   'paramlist': attributeParamlist(a, getter)}
-        return "%(scriptable)sNS_IMETHOD %(binaryname)s(%(paramlist)s)" % params
+        return "%(scriptable)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
 
 def methodNativeName(m):
     return m.binaryname is not None and m.binaryname or firstCap(m.name)
 
 def methodReturnType(m, macro):
     """macro should be NS_IMETHOD or NS_IMETHODIMP"""
-    if m.notxpcom:
+    if m.nostdcall and m.notxpcom:
+        return "%s%s" % (macro == "NS_IMETHOD" and "virtual " or "",
+                         m.realtype.nativeType('in').strip())
+    elif m.nostdcall:
+        return "%snsresult" % (macro == "NS_IMETHOD" and "virtual " or "")
+    elif m.notxpcom:
         return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
     else:
         return macro
 
 def methodAsNative(m):
     scriptable = m.isScriptable() and "NS_SCRIPTABLE " or ""
 
     return "%s%s %s(%s)" % (scriptable,
@@ -405,22 +418,22 @@ def write_interface(iface, fd):
 
     fd.write(iface_template_prolog % names)
 
     for member in iface.members:
         if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA): continue
         fd.write("/* %s */\n" % member.toIDL())
         if isinstance(member, xpidl.Attribute):
             fd.write(example_tmpl % {'implclass': implclass,
-                                     'returntype': 'NS_IMETHODIMP',
+                                     'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
                                      'nativeName': attributeNativeName(member, True),
                                      'paramList': attributeParamlist(member, True)})
             if not member.readonly:
                 fd.write(example_tmpl % {'implclass': implclass,
-                                         'returntype': 'NS_IMETHODIMP',
+                                         'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
                                          'nativeName': attributeNativeName(member, False),
                                          'paramList': attributeParamlist(member, False)})
         elif isinstance(member, xpidl.Method):
             fd.write(example_tmpl % {'implclass': implclass,
                                      'returntype': methodReturnType(member, 'NS_IMETHODIMP'),
                                      'nativeName': methodNativeName(member),
                                      'paramList': paramlistAsNative(member.params, member.realtype, notxpcom=member.notxpcom, empty='')})
         fd.write('\n')
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -643,16 +643,17 @@ class ConstMember(object):
         return "\tconst %s %s = %s\n" % (self.type, self.name, self.getValue())
 
 class Attribute(object):
     kind = 'attribute'
     noscript = False
     notxpcom = False
     readonly = False
     implicit_jscontext = False
+    nostdcall = False
     binaryname = None
     null = None
     undefined = None
 
     def __init__(self, type, name, attlist, readonly, location, doccomments):
         self.type = type
         self.name = name
         self.attlist = attlist
@@ -694,18 +695,20 @@ class Attribute(object):
                     raise IDLError("Unexpected attribute value", aloc)
 
                 if name == 'noscript':
                     self.noscript = True
                 elif name == 'notxpcom':
                     self.notxpcom = True
                 elif name == 'implicit_jscontext':
                     self.implicit_jscontext = True
+                elif name == 'nostdcall':
+                    self.nostdcall = True
                 else:
-                    raise IDLError("Unexpected attribute '%s'", aloc)
+                    raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
     def resolve(self, iface):
         self.iface = iface
         self.realtype = iface.idl.getName(self.type, self.location)
         if (self.null is not None and
             getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Null' attribute can only be used on DOMString",
                            self.location)
@@ -728,16 +731,17 @@ class Attribute(object):
                                           self.type, self.name)
 
 class Method(object):
     kind = 'method'
     noscript = False
     notxpcom = False
     binaryname = None
     implicit_jscontext = False
+    nostdcall = False
     optional_argc = False
 
     def __init__(self, type, name, attlist, paramlist, location, doccomments, raises):
         self.type = type
         self.name = name
         self.attlist = attlist
         self.params = paramlist
         self.location = location
@@ -759,18 +763,20 @@ class Method(object):
             if name == 'noscript':
                 self.noscript = True
             elif name == 'notxpcom':
                 self.notxpcom = True
             elif name == 'implicit_jscontext':
                 self.implicit_jscontext = True
             elif name == 'optional_argc':
                 self.optional_argc = True
+            elif name == 'nostdcall':
+                self.nostdcall = True
             else:
-                raise IDLError("Unexpected attribute '%s'", aloc)
+                raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
         self.namemap = NameMap()
         for p in paramlist:
             self.namemap.set(p)
 
     def resolve(self, iface):
         self.iface = iface
         self.realtype = self.iface.idl.getName(self.type, self.location)
--- a/xpcom/typelib/xpidl/xpidl_header.c
+++ b/xpcom/typelib/xpidl/xpidl_header.c
@@ -784,26 +784,34 @@ write_type(IDL_tree type_tree, write_typ
  */
 static gboolean
 write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
                     gboolean getter, int mode, const char *className)
 {
     char *attrname = ATTR_IDENT(attr_tree).str;
     const char *binaryname;
     IDL_tree ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data;
+    gboolean nostdcall =
+        (IDL_tree_property_get(ATTR_DECLS(attr_tree), "nostdcall") != NULL);
 
     if (mode == AS_DECL) {
         if (IDL_tree_property_get(ident, "deprecated"))
             fputs("MOZ_DEPRECATED ", outfile);
         if (is_method_scriptable(attr_tree, ident))
             fputs("NS_SCRIPTABLE ", outfile);
 
-        fputs("NS_IMETHOD ", outfile);
+        if (nostdcall)
+            fputs("virtual nsresult ", outfile);
+        else
+            fputs("NS_IMETHOD ", outfile);
     } else if (mode == AS_IMPL) {
-        fprintf(outfile, "NS_IMETHODIMP %s::", className);
+        if (nostdcall)
+            fprintf(outfile, "nsresult %s::", className);
+        else
+            fprintf(outfile, "NS_IMETHODIMP %s::", className);
     }
     fprintf(outfile, "%cet",
             getter ? 'G' : 'S');
     binaryname = IDL_tree_property_get(ATTR_DECLS(attr_tree), "binaryname");
     if (binaryname) {
         fprintf(outfile, "%s(",
                 binaryname);
     } else {
@@ -1035,38 +1043,59 @@ write_method_signature(IDL_tree method_t
     struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
     gboolean no_generated_args = TRUE;
     gboolean op_notxpcom =
         (IDL_tree_property_get(op->ident, "notxpcom") != NULL);
     gboolean op_opt_argc =
         (IDL_tree_property_get(op->ident, "optional_argc") != NULL);
     gboolean op_context =
         (IDL_tree_property_get(op->ident, "implicit_jscontext") != NULL);
+    gboolean op_nostdcall =
+        (IDL_tree_property_get(op->ident, "nostdcall") != NULL);
     const char *name;
     const char *binaryname;
     IDL_tree iter;
 
     if (mode == AS_DECL) {
         if (IDL_tree_property_get(op->ident, "deprecated"))
             fputs("MOZ_DEPRECATED ", outfile);
         if (is_method_scriptable(method_tree, op->ident))
             fputs("NS_SCRIPTABLE ", outfile);
 
-        if (op_notxpcom) {
+        if (op_nostdcall) {
+            fputs("virtual ", outfile);
+            if (op_notxpcom) {
+                if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile))
+                    return FALSE;
+            }
+            else {
+                fputs("nsresult", outfile);
+            }
+        }
+        else if (op_notxpcom) {
             fputs("NS_IMETHOD_(", outfile);
             if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile))
                 return FALSE;
             fputc(')', outfile);
         } else {
             fputs("NS_IMETHOD", outfile);
         }
         fputc(' ', outfile);
     }
     else if (mode == AS_IMPL) {
-        if (op_notxpcom) {
+        if (op_nostdcall) {
+            if (op_notxpcom) {
+                if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile))
+                    return FALSE;
+            }
+            else {
+                fputs("nsresult", outfile);
+            }
+        }
+        else if (op_notxpcom) {
             fputs("NS_IMETHODIMP_(", outfile);
             if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile))
                 return FALSE;
             fputc(')', outfile);
         } else {
             fputs("NS_IMETHODIMP", outfile);
         }
         fputc(' ', outfile);
--- a/xpcom/typelib/xpidl/xpidl_util.c
+++ b/xpcom/typelib/xpidl/xpidl_util.c
@@ -355,16 +355,22 @@ verify_attribute_declaration(IDL_tree at
     /*
      * If the interface isn't scriptable, or the attribute is marked noscript,
      * there's no need to check. This also verifies that we've been called on
      * an interface.
      */
     if (!is_method_scriptable(attr_tree, ident))
         return TRUE;
 
+    if (IDL_tree_property_get(ident, "nostdcall") != NULL) {
+        IDL_tree_error(attr_tree,
+                       "[nostdcall] attribute must not be scriptable");
+        return FALSE;
+    }
+
     /*
      * If it should be scriptable, check that the type is non-native. nsid,
      * domstring, utf8string, cstring, astring are exempted.
      */
     attr_type = IDL_ATTR_DCL(attr_tree).param_type_spec;
 
     if (attr_type != NULL)
     {
@@ -774,17 +780,24 @@ verify_method_declaration(IDL_tree metho
 
     if (IDL_tree_property_get(op->ident, "optional_argc") != NULL &&
         !hasoptional) {
         IDL_tree_error(method_tree,
                        "[optional_argc] method must contain [optional] "
                        "arguments");
         return FALSE;
     }
-    
+
+    if (IDL_tree_property_get(op->ident, "nostdcall") != NULL &&
+        scriptable_method) {
+        IDL_tree_error(method_tree,
+                       "[nostdcall] method must not be scriptable");
+        return FALSE;
+    }
+
     /* XXX q: can return type be nsid? */
     /* Native return type? */
     if (scriptable_method &&
         op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) &&
         IDL_tree_property_get(op->op_type_spec, "nsid") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "domstring") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "cstring") == NULL &&