Passing lots of stuff now!
authorBenjamin Smedberg <benjamin@smedbergs.us>
Sun, 15 Jun 2008 10:38:28 -0400
changeset 8 ea4b1c101668
parent 7 c9cc546fc95a
child 9 521ac1e42cbb
push id7
push userbsmedberg@mozilla.com
push date2008-06-15 14:38 +0000
Passing lots of stuff now!
header.py
testheaderrules.mk
xpidl.py
--- a/header.py
+++ b/header.py
@@ -2,62 +2,86 @@
 
 """Print a C++ header file for the IDL files specified on the command line"""
 
 import sys, os.path, re, xpidl
 
 def firstCap(str):
     return str[0].upper() + str[1:]
 
+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 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 ""
-        binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
-        paramname = "a" + firstCap(a.name)
+        params = {'scriptable': scriptable,
+                  'binaryname': attributeNativeName(a, getter),
+                  'paramlist': attributeParamlist(a, getter)}
+        return "%(scriptable)sNS_IMETHOD %(binaryname)s(%(paramlist)s)" % params
 
-        params = {'scriptable': scriptable,
-                  'binaryname': binaryname,
-                  'paramname': paramname,
-                  'type': a.realtype.nativeType(getter and 'out' or 'in'),
-                  'get': getter and 'Get' or 'Set'}
-        return "%(scriptable)sNS_IMETHOD %(get)s%(binaryname)s(%(type)s%(paramname)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:
+        return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
+    else:
+        return macro
 
 def methodAsNative(m):
     scriptable = m.isScriptable() and "NS_SCRIPTABLE " or ""
-    binaryname = m.binaryname is not None and m.binaryname or firstCap(m.name)
 
-    return "%sNS_IMETHOD %s(%s)" % (scriptable,
-                                    binaryname,
-                                    paramlistAsNative(m.params, m.realtype))
+    return "%s%s %s(%s)" % (scriptable,
+                            methodReturnType(m, 'NS_IMETHOD'),
+                            methodNativeName(m),
+                            paramlistAsNative(m.params,
+                                              m.realtype,
+                                              notxpcom=m.notxpcom))
 
-def paramlistAsNative(l, rettype):
+def paramlistAsNative(l, rettype, notxpcom, empty='void'):
     l = list(l)
-    if rettype.name != 'void':
+    if not notxpcom and rettype.name != 'void':
         l.append(xpidl.Param(paramtype='out',
                              type=None,
                              name='_retval',
                              attlist=[],
                              location=None,
                              realtype=rettype))
 
     if len(l) == 0:
-        return 'void'
+        return empty
 
     return ", ".join([paramAsNative(p) for p in l])
 
 def paramAsNative(p):
     if p.paramtype == 'in':
         typeannotate = ''
     else:
         typeannotate = ' NS_%sPARAM' % p.paramtype.upper()
 
-    return "%s%s%s" % (p.realtype.nativeType(p.paramtype),
+    return "%s%s%s" % (p.nativeType(),
                        p.name,
                        typeannotate)
 
-    
+def paramlistNames(l, rettype, notxpcom):
+    names = [p.name for p in l]
+    if not notxpcom and rettype.name != 'void':
+        names.append('_retval')
+    if len(names) == 0:
+        return ''
+    return ', '.join(names)
 
 header = """/*
  * DO NOT EDIT.  THIS FILE IS GENERATED FROM %(filename)s
  */
 
 #ifndef __gen_%(basename)s_h__
 #define __gen_%(basename)s_h__
 """
@@ -85,19 +109,21 @@ forward_decl = """class %(name)s; /* for
 def idl_basename(f):
     """returns the base name of a file with the last extension stripped"""
     return os.path.basename(f).rpartition('.')[0]
 
 def print_header(idl, fd, filename):
     fd.write(header % {'filename': filename,
                        'basename': idl_basename(filename)})
 
-    inccount = 0
+    foundinc = False
     for inc in idl.includes():
-        fd.write('\n')
+        if not foundinc:
+            foundinc = True
+            fd.write('\n')
         fd.write(include % {'basename': idl_basename(inc.filename)})
 
     fd.write('\n')
     fd.write(header_end)
 
     for p in idl.productions:
         if p.kind == 'include': continue
         if p.kind == 'cdata':
@@ -135,87 +161,233 @@ iface_prolog = """ {
   NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
 
 """
 
 iface_epilog = """};
 
   NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
 
+/* Use this macro when declaring classes that implement this interface. */
+#define NS_DECL_%(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) """
+
+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) """
+
+iface_template_prolog = """
+
+#if 0
+/* Use the code below as a template for the implementation class for this interface. */
+
+/* Header file */
+class %(implclass)s : public %(name)s
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_%(macroname)s
+
+  %(implclass)s();
+
+private:
+  ~%(implclass)s();
+
+protected:
+  /* additional members */
+};
+
+/* Implementation file */
+NS_IMPL_ISUPPORTS1(%(implclass)s, %(name)s)
+
+%(implclass)s::%(implclass)s()
+{
+  /* member initializers and constructor code */
+}
+
+%(implclass)s::~%(implclass)s()
+{
+  /* destructor code */
+}
+
+"""
+
+example_tmpl = """%(returntype)s %(implclass)s::%(nativeName)s(%(paramList)s)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+"""
+
+iface_template_epilog = """/* End of implementation class template. */
+#endif
+
 """
 
 def write_interface(iface, fd):
     if iface.namemap is None:
         raise Exception("Interface was not resolved.")
 
-    def write_const(c):
+    def write_const_decl(c):
         for comment in c.doccomments:
             fd.write("  %s\n" % comment)
 
         basetype = c.basetype
         value = c.getValue(iface)
 
         fd.write("  enum { %(name)s = %(value)s%(signed)s };\n\n" % {
                      'name': c.name,
                      'value': value,
                      'signed': (not basetype.signed) and 'U' or ''})
 
-    def write_method(c):
-        for comment in c.doccomments:
+    def write_method_decl(m):
+        for comment in m.doccomments:
             fd.write("  %s\n" % comment)
 
-        fd.write("  /* %s */\n" % c.toIDL())
-        fd.write("  %s = 0;\n\n" % methodAsNative(c))
+        fd.write("  /* %s */\n" % m.toIDL())
+        fd.write("  %s = 0;\n\n" % methodAsNative(m))
                                                                            
-    def write_attr(c):
-        for comment in c.doccomments:
+    def write_attr_decl(a):
+        for comment in a.doccomments:
             fd.write("  %s\n" % comment)
 
-        fd.write("  /* %s */\n" % c.toIDL());
+        fd.write("  /* %s */\n" % a.toIDL());
 
-        fd.write("  %s = 0;\n" % attributeAsNative(c, True))
-        if not c.readonly:
-            fd.write("  %s = 0;\n" % attributeAsNative(c, False))
+        fd.write("  %s = 0;\n" % attributeAsNative(a, True))
+        if not a.readonly:
+            fd.write("  %s = 0;\n" % attributeAsNative(a, False))
         fd.write("\n")
 
     defname = iface.name.upper()
     if iface.name[0:2] == 'ns':
         defname = 'NS_' + defname[2:]
 
     names = uuid_decoder.match(iface.attributes.uuid).groupdict()
     m3str = names['m3'] + names['m4']
     names['m3joined'] = ", ".join(["0x%s" % m3str[i:i+2] for i in xrange(0, 16, 2)])
 
+    if iface.name[2] == 'I':
+        implclass = iface.name[:2] + iface.name[3:]
+    else:
+        implclass = '_MYCLASS_'
+
     names.update({'defname': defname,
+                  'macroname': iface.name.upper(),
                   'name': iface.name,
-                  'iid': iface.attributes.uuid})
+                  'iid': iface.attributes.uuid,
+                  'implclass': implclass})
 
     fd.write(iface_header % names)
 
     for comment in iface.doccomments:
         fd.write("%s\n" % comment)
 
-    fd.write("class NS_NO_VTABLE ")
+    fd.write("class ")
+    foundcdata = False
+    for m in iface.members:
+        if isinstance(m, xpidl.CDATA):
+            foundcdata = True
+
+    if not foundcdata:
+        fd.write("NS_NO_VTABLE ")
+
     if iface.attributes.scriptable:
         fd.write("NS_SCRIPTABLE ")
     if iface.attributes.deprecated:
         fd.write("NS_DEPRECATED ")
     fd.write(iface.name)
     if iface.base:
         fd.write(" : public %s" % iface.base)
     fd.write(iface_prolog % names)
     for member in iface.members:
         if isinstance(member, xpidl.ConstMember):
-            write_const(member)
+            write_const_decl(member)
         elif isinstance(member, xpidl.Attribute):
-            write_attr(member)
+            write_attr_decl(member)
         elif isinstance(member, xpidl.Method):
-            write_method(member)
+            write_method_decl(member)
+        elif isinstance(member, xpidl.CDATA):
+            fd.write("  %s" % member.data)
         else:
             raise Exception("Unexpected interface member: %s" % member)
 
     fd.write(iface_epilog % names)
 
+    written = False
+    for member in iface.members:
+        if isinstance(member, xpidl.Attribute):
+            fd.write("\\\n  %s; " % attributeAsNative(member, True))
+            if not member.readonly:
+                fd.write("\\\n  %s; " % attributeAsNative(member, False))
+            written = True
+        elif isinstance(member, xpidl.Method):
+            fd.write("\\\n  %s; " % methodAsNative(member))
+            written = True
+    if not written:
+        fd.write('\\')
+
+    fd.write(iface_forward % names)
+
+    def emitTemplate(tmpl):
+        written = False
+        for member in iface.members:
+            if isinstance(member, xpidl.Attribute):
+                fd.write(tmpl % {'asNative': attributeAsNative(member, True),
+                                 'nativeName': attributeNativeName(member, True),
+                                 'paramList': attributeParamName(member)})
+                if not member.readonly:
+                    fd.write(tmpl % {'asNative': attributeAsNative(member, False),
+                                     'nativeName': attributeNativeName(member, False),
+                                     'paramList': attributeParamName(member)})
+                written = True
+            elif isinstance(member, xpidl.Method):
+                fd.write(tmpl % {'asNative': methodAsNative(member),
+                                 'nativeName': methodNativeName(member),
+                                 'paramList': paramlistNames(member.params, member.realtype, member.notxpcom)})
+                written = True
+        if not written:
+            fd.write('\\')
+
+    emitTemplate("\\\n  %(asNative)s { return _to %(nativeName)s(%(paramList)s); } ")
+
+    fd.write(iface_forward_safe % names)
+
+    emitTemplate("\\\n  %(asNative)s { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ")
+
+    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',
+                                     'nativeName': attributeNativeName(member, True),
+                                     'paramList': attributeParamlist(member, True)})
+            if not member.readonly:
+                fd.write(example_tmpl % {'implclass': implclass,
+                                         'returntype': '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')
+
+    fd.write(iface_template_epilog)
+
 if __name__ == '__main__':
+    from optparse import OptionParser
+    o = OptionParser()
+    o.add_option('-I', action='append', dest='incdirs', help="Directory to search for imported files", default=[])
+    options, args = o.parse_args()
+    file, = args
     p = xpidl.IDLParser()
-    idl = p.parse(open(sys.argv[1]).read(), filename=sys.argv[1])
-    idl.resolve(['/builds/mozilla-central/src/xpcom/base'])
+    idl = p.parse(open(file).read(), filename=file)
+    idl.resolve(options.incdirs)
     print_header(idl, sys.stdout, sys.argv[1])
new file mode 100644
--- /dev/null
+++ b/testheaderrules.mk
@@ -0,0 +1,9 @@
+# Copy this to objdir/myrules.mk to test
+
+ifneq ($(XPIDLSRCS)$(SDK_XPIDLSRCS),)
+export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.pyh, $(XPIDLSRCS))
+endif
+
+$(XPIDL_GEN_DIR)/%.pyh: %.idl $(XPIDL_GEN_DIR)/%.h
+	python /builds/idl-parser/header.py $< $(XPIDL_FLAGS) > $@
+	diff -w -U 3 $(XPIDL_GEN_DIR)/$*.h $@
--- a/xpidl.py
+++ b/xpidl.py
@@ -1,13 +1,13 @@
 #!/usr/bin/env python
 
 """A parser for cross-platform IDL (XPIDL) files."""
 
-import lex, yacc, sys, os.path
+import lex, yacc, sys, os.path, re
 
 """A type conforms to the following pattern:
 
     def isScriptable(self):
         'returns True or False'
 
     def nativeType(self, calltype):
         'returns a string representation of the native type
@@ -20,19 +20,29 @@ Interface members const/method/attribute
     def toIDL(self):
         'returns the member signature as IDL'
 """
 
 def attlistToIDL(attlist):
     if len(attlist) == 0:
         return ''
 
+    attlist = list(attlist)
+    attlist.sort(cmp=lambda a,b: cmp(a[0], b[0]))
+
     return '[%s] ' % ','.join(["%s%s" % (name, value is not None and '(%s)' % value or '')
                               for name, value, aloc in attlist])
 
+def paramAttlistToIDL(attlist):
+    if len(attlist) == 0:
+        return ''
+
+    return '[%s] ' % ', '.join(["%s%s" % (name, value is not None and ' (%s)' % value or '')
+                                for name, value, aloc in attlist])
+
 class BuiltinLocation(object):
     def get(self):
         return "<builtin type>"
 
     def __str__(self):
         return self.get()
 
 class Builtin(object):
@@ -42,19 +52,27 @@ class Builtin(object):
         self.name = name
         self.nativename = nativename
         self.signed = signed
         self.maybeConst = maybeConst
 
     def isScriptable(self):
         return True
 
-    def nativeType(self, calltype):
-        return "%s %s" % (self.nativename,
-                          calltype != 'in' and '*' or '')
+    def nativeType(self, calltype, shared=False):
+        if calltype == 'in' and self.nativename.endswith('*'):
+            const = 'const '
+        elif shared:
+            if not self.nativename.endswith('*'):
+                raise XPIDLError("[shared] not applicable to non-pointer types.")
+            const = 'const '
+        else:
+            const = ''
+        return "%s%s %s" % (const, self.nativename,
+                            calltype != 'in' and '*' or '')
 
 builtinNames = [
     Builtin('boolean', 'PRBool'),
     Builtin('void', 'void'),
     Builtin('octet', 'unsigned char'),
     Builtin('short', 'PRInt16', True, True),
     Builtin('long', 'PRInt32', True, True),
     Builtin('long long', 'PRInt64', True, False),
@@ -77,16 +95,20 @@ class Location(object):
     _line = None
 
     def __init__(self, lexer, lineno, lexpos):
         self._lineno = lineno
         self._lexpos = lexpos
         self._lexdata = lexer.lexdata
         self._file = getattr(lexer, 'filename', "<unknown>")
 
+    def __eq__(self, other):
+        return self._lexpos == other._lexpos and \
+               self._file == other._file
+
     def resolve(self):
         if self._line:
             return
 
         startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1
         endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80)
         self._line = self._lexdata[startofline:endofline]
         self._colno = self._lexpos - startofline
@@ -121,19 +143,26 @@ class NameMap(object):
 
     def __iter__(self):
         return self._d.itervalues()
 
     def set(self, object):
         if object.name in builtinMap:
             raise IDLError("name '%s' is a builtin and cannot be redeclared" % (object.name), object.location)
         if object.name in self._d:
-            raise IDLError("name '%s' specified twice. Previous location: %s" % (object.name, d[object.name].location), object.location)
-
-        self._d[object.name] = object
+            old = self._d[object.name]
+            if old == object: return
+            if isinstance(old, Forward) and isinstance(object, Interface):
+                self._d[object.name] = object
+            elif isinstance(old, Interface) and isinstance(object, Forward):
+                pass
+            else:
+                raise IDLError("name '%s' specified twice. Previous location: %s" % (object.name, self._d[object.name].location), object.location)
+        else:
+            self._d[object.name] = object
 
 class IDLError(Exception):
     def __init__(self, message, location):
         self.message = message
         self.location = location
 
     def __str__(self):
         return "Error: %s, %s" % (self.message, self.location)
@@ -192,19 +221,20 @@ class IDL(object):
 
     def includes(self):
         for p in self.productions:
             if p.kind == 'include':
                 yield p
 
 class CDATA(object):
     kind = 'cdata'
+    _re = re.compile(r'\n+')
 
     def __init__(self, data, location):
-        self.data = data
+        self.data = self._re.sub('\n', data)
         self.location = location
 
     def resolve(self, parent):
         pass
 
     def __str__(self):
         return "cdata: %s\n\t%r\n" % (self.location.get(), self.data)
 
@@ -212,16 +242,19 @@ class Typedef(object):
     kind = 'typedef'
 
     def __init__(self, type, name, location):
         self.type = type
         self.name = name
         self.location = location
         self.nativename = name
 
+    def __eq__(self, other):
+        return self.name == other.name and self.type == other.type
+
     def resolve(self, parent):
         parent.setName(self)
         self.realtype = parent.getName(self.type, self.location)
 
     def isScriptable(self):
         return self.realtype.isScriptable()
 
     def nativeType(self, calltype):
@@ -232,17 +265,19 @@ class Typedef(object):
         return "typedef %s %s\n" % (self.type, self.name)
 
 class Forward(object):
     kind = 'forward'
 
     def __init__(self, name, location):
         self.name = name
         self.location = location
-        self.nativename = name
+
+    def __eq__(self, other):
+        return other.kind == 'forward' and other.name == self.name
 
     def resolve(self, parent):
         parent.setName(self)
 
     def isScriptable(self):
         return True
 
     def nativeType(self, calltype):
@@ -252,72 +287,76 @@ class Forward(object):
     def __str__(self):
         return "forward-declared %s\n" % self.name
 
 class Native(object):
     kind = 'native'
 
     modifier = None
     specialtype = None
-    scriptable = False
 
     specialtypes = {
-        'nsid': 'nsID',
+        'nsid': None,
         'domstring': 'nsAString',
         'utf8string': 'nsACString',
         'cstring': 'nsACString',
         'astring': 'nsAString'
         }
-        
+
     def __init__(self, name, nativename, attlist, location):
         self.name = name
         self.nativename = nativename
         self.location = location
 
         for name, value, aloc in attlist:
             if value is not None:
                 raise IDLError("Unexpected attribute value", aloc)
             if name in ('ptr', 'ref'):
                 if self.modifier is not None:
                     raise IDLError("More than one ptr/ref modifier", aloc)
                 self.modifier = name
             elif name in self.specialtypes.keys():
                 if self.specialtype is not None:
                     raise IDLError("More than one special type", aloc)
                 self.specialtype = name
-                self.nativename = self.specialtypes[name]
-                self.scriptable = True
+                if self.specialtypes[name] is not None:
+                    self.nativename = self.specialtypes[name]
             else:
                 raise IDLError("Unexpected attribute", aloc)
 
-        if self.specialtype != 'nsid' and self.modifier is None:
-            raise IDLError("Native string type is neither 'ref' nor 'ptr'",
-                           location)
+    def __eq__(self, other):
+        return self.name == other.name and \
+               self.nativename == other.nativename and \
+               self.modifier == other.modifier and \
+               self.specialtype == other.specialtype
 
     def resolve(self, parent):
         parent.setName(self)
 
     def isScriptable(self):
         if self.specialtype is None:
             return False
 
         if self.specialtype == 'nsid':
             return self.modifier is not None
 
         return self.modifier == 'ref'
 
     def nativeType(self, calltype):
-        const = ''
+        if self.specialtype is not None and calltype == 'in':
+            const = 'const '
+        else:
+            const = ''
+
         if self.modifier == 'ptr':
-            m = '*'
+            m = '*' + (calltype != 'in' and '*' or '')
         elif self.modifier == 'ref':
             m = '& '
-            if calltype == 'in': const = 'const '
         else:
-            m = ''
+            m = calltype != 'in' and '*' or ''
         return "%s%s %s" % (const, self.nativename, m)
 
     def __str__(self):
         return "native %s(%s)\n" % (self.name, self.nativename)
 
 class Interface(object):
     kind = 'interface'
 
@@ -330,16 +369,19 @@ class Interface(object):
         self.namemap = NameMap()
         self.doccomments = doccomments
         self.nativename = name
 
         for m in members:
             if not isinstance(m, CDATA):
                 self.namemap.set(m)
 
+    def __eq__(self, other):
+        return self.name == other.name and self.location == other.location
+
     def resolve(self, parent):
         self.idl = parent
         parent.setName(self)
         if self.base is None:
             if self.name != 'nsISupports':
                 raise IDLError("interface '%s' not derived from nsISupports",
                                self.location)
         else:
@@ -354,19 +396,20 @@ class Interface(object):
             member.resolve(self)
 
     def isScriptable(self):
         # NOTE: this is not whether *this* interface is scriptable... it's
         # whether, when used as a type, it's scriptable, which is true of all
         # interfaces.
         return True
 
-    def nativeType(self, calltype):
-        return "%s %s" % (self.name,
-                          calltype != 'in' and '* *' or '*')
+    def nativeType(self, calltype, const=False):
+        return "%s%s %s" % (const and 'const ' or '',
+                            self.name,
+                            calltype != 'in' and '* *' or '*')
 
     def __str__(self):
         l = ["interface %s\n" % self.name]
         if self.base is not None:
             l.append("\tbase %s\n" % self.base)
         l.append(str(self.attributes))
         if self.members is None:
             l.append("\tincomplete type\n")
@@ -614,23 +657,47 @@ class Param(object):
                     self.shared = True
                 elif name == 'optional':
                     self.optional = True
                 else:
                     raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
     def resolve(self, method):
         self.realtype = method.iface.idl.getName(self.type, self.location)
+        if self.array:
+            self.realtype = Array(self.realtype)
+
+    def nativeType(self):
+        kwargs = {}
+        if self.shared: kwargs['shared'] = True
+        if self.const: kwargs['const'] = True
+
+        try:
+            return self.realtype.nativeType(self.paramtype, **kwargs)
+        except IDLError, e:
+            raise IDLError(e.message, self.location)
+        except TypeError, e:
+            raise IDLError("Unexpected paramater attribute", self.location)
 
     def toIDL(self):
-        return "%s%s %s %s" % (attlistToIDL(self.attlist),
+        return "%s%s %s %s" % (paramAttlistToIDL(self.attlist),
                                self.paramtype,
                                self.type,
                                self.name)
 
+class Array(object):
+    def __init__(self, basetype):
+        self.type = basetype
+
+    def isScriptable(self):
+        return self.type.isScriptable()
+
+    def nativeType(self, calltype):
+        return self.type.nativeType(calltype) + "*"
+
 class IDLParser(object):
     keywords = {
         'const': 'CONST',
         'interface': 'INTERFACE',
         'in': 'IN',
         'inout': 'INOUT',
         'out': 'OUT',
         'attribute': 'ATTRIBUTE',
@@ -968,17 +1035,17 @@ class IDLParser(object):
         p[0].insert(0, p[2])
 
     def p_param(self, p):
         """param : attributes paramtype IDENTIFIER IDENTIFIER"""
         p[0] = Param(paramtype=p[2],
                      type=p[3],
                      name=p[4],
                      attlist=p[1]['attlist'],
-                     location=self.getLocation(p, 1))
+                     location=self.getLocation(p, 3))
 
     def p_paramtype(self, p):
         """paramtype : IN
                      | INOUT
                      | OUT"""
         p[0] = p[1]
 
     def p_optreadonly(self, p):