Comments really really suck! Now I'm just going to remove them and see if I can convince shaver, at least temporarily.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Thu, 19 Jun 2008 12:24:36 -0400
changeset 11 024b54ccabc6
parent 10 3394439f0ddc
child 12 30574df5c435
push id9
push userbsmedberg@mozilla.com
push dateThu, 19 Jun 2008 17:57:09 +0000
Comments really really suck! Now I'm just going to remove them and see if I can convince shaver, at least temporarily.
header.py
testheaderrules.mk
xpidl.py
--- a/header.py
+++ b/header.py
@@ -382,14 +382,19 @@ def write_interface(iface, fd):
         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=[])
+    o.add_option('--cachedir', dest='cachedir', help="Directory in which to cache lex/parse tables.", default='')
     options, args = o.parse_args()
     file, = args
-    p = xpidl.IDLParser()
+
+    if options.cachedir != '':
+        sys.path.append(options.cachedir)
+
+    p = xpidl.IDLParser(outputdir=options.cachedir)
     idl = p.parse(open(file).read(), filename=file)
-    idl.resolve(options.incdirs)
-    print_header(idl, sys.stdout, sys.argv[1])
+    idl.resolve(options.incdirs, p)
+    print_header(idl, sys.stdout, file)
--- a/testheaderrules.mk
+++ b/testheaderrules.mk
@@ -1,9 +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 /builds/idl-parser/header.py /builds/idl-parser/xpidl.py
-	python /builds/idl-parser/header.py $< $(XPIDL_FLAGS) > $@
+	python /builds/idl-parser/header.py --cachedir=$(DEPTH)/config $(XPIDL_FLAGS) $< > $@
 	diff -w -B -U 3 $(XPIDL_GEN_DIR)/$*.h $@
--- a/xpidl.py
+++ b/xpidl.py
@@ -214,18 +214,18 @@ class Include(object):
         def incfiles():
             yield self.filename
             for dir in parent.incdirs:
                 yield os.path.join(dir, self.filename)
 
         for file in incfiles():
             if not os.path.exists(file): continue
 
-            self.IDL = IDLParser().parse(open(file).read(), filename=file)
-            self.IDL.resolve(parent.incdirs)
+            self.IDL = parent.parser.parse(open(file).read(), filename=file)
+            self.IDL.resolve(parent.incdirs, parent.parser)
             for type in self.IDL.getNames():
                 parent.setName(type)
             return
 
         raise IDLError("File '%s' not found" % self.filename, self.location)
 
 class IDL(object):
     def __init__(self, productions):
@@ -244,19 +244,20 @@ class IDL(object):
         return id in self.namemap
 
     def getNames(self):
         return iter(self.namemap)
 
     def __str__(self):
         return "".join([str(p) for p in self.productions])
 
-    def resolve(self, incdirs):
+    def resolve(self, incdirs, parser):
         self.namemap = NameMap()
         self.incdirs = incdirs
+        self.parser = parser
         for p in self.productions:
             p.resolve(self)
 
     def includes(self):
         for p in self.productions:
             if p.kind == 'include':
                 yield p
 
@@ -284,19 +285,16 @@ class Typedef(object):
         self.doccomments = doccomments
 
     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)
-        if isinstance(self.realtype, Native):
-            raise IDLError("Typedefs of native types are not supported.", 
-                           self.location)
 
     def isScriptable(self):
         return self.realtype.isScriptable()
 
     def nativeType(self, calltype):
         return "%s %s" % (self.name,
                           calltype != 'in' and '*' or '')
 
@@ -310,16 +308,26 @@ class Forward(object):
         self.name = name
         self.location = location
         self.doccomments = doccomments
 
     def __eq__(self, other):
         return other.kind == 'forward' and other.name == self.name
 
     def resolve(self, parent):
+        # Hack alert: if an identifier is already present, move the doccomments
+        # forward.
+        if parent.hasName(self.name):
+            for i in xrange(0, len(parent.productions)):
+                if parent.productions[i] is self: break
+            for i in xrange(i + 1, len(parent.productions)):
+                if hasattr(parent.productions[i], 'doccomments'):
+                    parent.productions[i].doccomments[0:0] = self.doccomments
+                    break
+
         parent.setName(self)
 
     def isScriptable(self):
         return True
 
     def nativeType(self, calltype):
         return "%s %s" % (self.name,
                           calltype != 'in' and '* *' or '*')
@@ -423,17 +431,16 @@ class Interface(object):
     def resolve(self, parent):
         self.idl = parent
 
         # Hack alert: if an identifier is already present, libIDL assigns
         # doc comments incorrectly. This is quirks-mode extraordinaire!
         if parent.hasName(self.name):
             for member in self.members:
                 if hasattr(member, 'doccomments'):
-                    print >>sys.stderr, "Moving comments to %s" % member
                     member.doccomments[0:0] = self.doccomments
                     break
             self.doccomments = parent.getName(self.name, None).doccomments
 
         parent.setName(self)
         if self.base is None:
             if self.name != 'nsISupports':
                 print >>sys.stderr, IDLError("interface '%s' not derived from nsISupports",
@@ -615,23 +622,24 @@ class Attribute(object):
                                           self.type, self.name)
 
 class Method(object):
     kind = 'method'
     noscript = False
     notxpcom = False
     binaryname = None
 
-    def __init__(self, type, name, attlist, paramlist, location, doccomments):
+    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
         self.doccomments = doccomments
+        self.raises = raises
 
         for name, value, aloc in attlist:
             if name == 'binaryname':
                 if value is None:
                     raise IDLError("binaryname attribute requires a value",
                                    aloc)
 
                 self.binaryname = value
@@ -660,21 +668,27 @@ class Method(object):
     def isScriptable(self):
         if not self.iface.attributes.scriptable: return False
         return not (self.noscript or self.notxpcom)
 
     def __str__(self):
         return "\t%s %s(%s)\n" % (self.type, self.name, ", ".join([p.name for p in self.params]))
 
     def toIDL(self):
-        return "%s%s %s (%s);" % (attlistToIDL(self.attlist),
-                                  self.type,
-                                  self.name,
-                                  ", ".join([p.toIDL()
-                                             for p in self.params]))
+        if len(self.raises):
+            raises = ' raises (%s)' % ','.join(self.raises)
+        else:
+            raises = ''
+
+        return "%s%s %s (%s)%s;" % (attlistToIDL(self.attlist),
+                                    self.type,
+                                    self.name,
+                                    ", ".join([p.toIDL()
+                                               for p in self.params]),
+                                    raises)
 
 class Param(object):
     size_is = None
     iid_is = None
     const = False
     array = False
     retval = False
     shared = False
@@ -807,44 +821,51 @@ class IDLParser(object):
     t_IID.__doc__ = r'%(c)s{8}-%(c)s{4}-%(c)s{4}-%(c)s{4}-%(c)s{12}' % {'c': hexchar}
 
     def t_IDENTIFIER(self, t):
         r'unsigned\ long\ long|unsigned\ short|unsigned\ long|long\ long|[A-Za-z][A-Za-z_0-9]*'
         t.type = self.keywords.get(t.value, 'IDENTIFIER')
         return t
 
     def t_LCDATA(self, t):
-        r'%\{[ ]*C\+\+\s*\n(?s)(?P<cdata>.*?\n?)%\}[ ]*(C\+\+)?'
+        r'(?s)%\{[ ]*C\+\+[ ]*\n(?P<cdata>.*?\n?)%\}[ ]*(C\+\+)?'
         t.type = 'CDATA'
         t.value = t.lexer.lexmatch.group('cdata')
         t.lexer.lineno += t.value.count('\n')
         return t
 
     def t_INCLUDE(self, t):
         r'\#include[ \t]+"[^"\n]+"'
         inc, value, end = t.value.split('"')
         t.value = value
         return t
 
+    def t_directive(self, t):
+        r'\#(?P<directive>[a-zA-Z]+)[^\n]+'
+        print >>sys.stderr, IDLError("Unrecognized directive %s" % t.lexer.lexmatch.group('directive'),
+                                     Location(lexer=self.lexer,
+                                              lineno=self.lexer.lineno,
+                                              lexpos=self.lexer.lexpos))
+
     def t_newline(self, t):
         r'\n+'
         t.lexer.lineno += len(t.value)
 
     def t_nativeid_NATIVEID(self, t):
         r'[^()\n]+(?=\))'
         t.lexer.begin('INITIAL')
         return t
 
     t_nativeid_ignore = ''
 
     def t_ANY_error(self, t):
         raise IDLError("unrecognized input",
-                         Location(lexer=self.lexer,
-                                         lineno=self.lexer.lineno,
-                                         lexpos=self.lexer.lexpos))
+                       Location(lexer=self.lexer,
+                                lineno=self.lexer.lineno,
+                                lexpos=self.lexer.lexpos))
 
     precedence = (
         ('left', '|'),
         ('left', 'LSHIFT', 'RSHIFT'),
         ('left', '+', '-'),
         ('left', 'UMINUS'),
     )
 
@@ -1062,23 +1083,23 @@ class IDLParser(object):
 
     def p_member_method(self, p):
         """member : attributes IDENTIFIER IDENTIFIER '(' paramlist ')' raises ';'"""
         if 'doccomments' in p[1]:
             doccomments = p[1]['doccomments']
         else:
             doccomments = p.slice[2].doccomments
 
-        # Ignoring "raises" for the moment, because I think it's unused
         p[0] = Method(type=p[2],
                       name=p[3],
                       attlist=p[1]['attlist'],
                       paramlist=p[5],
                       location=self.getLocation(p, 1),
-                      doccomments=doccomments)
+                      doccomments=doccomments,
+                      raises=p[7])
 
     def p_paramlist(self, p):
         """paramlist : param moreparams
                      | """
         if len(p) == 1:
             p[0] = []
         else:
             p[0] = list(p[2])
@@ -1113,31 +1134,45 @@ class IDLParser(object):
         if len(p) > 1:
             p[0] = p.slice[1].doccomments
         else:
             p[0] = None
 
     def p_raises(self, p):
         """raises : RAISES '(' idlist ')'
                   | """
+        if len(p) == 1:
+            p[0] = []
+        else:
+            p[0] = p[3]
 
     def p_idlist(self, p):
         """idlist : IDENTIFIER"""
+        p[0] = [p[1]]
 
     def p_idlist_continue(self, p):
         """idlist : IDENTIFIER ',' idlist"""
+        p[0] = list(p[3])
+        p[0].insert(0, p[1])
 
     def p_error(self, t):
         location = Location(self.lexer, t.lineno, t.lexpos)
         raise IDLError("invalid syntax", location)
 
-    def __init__(self):
+    def __init__(self, outputdir=''):
         self._doccomments = []
-        self.lexer = lex.lex(object=self)
-        self.parser = yacc.yacc(module=self)
+        self.lexer = lex.lex(object=self,
+                             outputdir=outputdir,
+                             lextab='xpidllex',
+                             optimize=1)
+        self.parser = yacc.yacc(module=self,
+                                outputdir=outputdir,
+                                debugfile='xpidl_debug',
+                                tabmodule='xpidlyacc',
+                                optimize=1)
 
     def clearComments(self):
         self._doccomments = []
 
     def token(self):
         t = self.lexer.token()
         if t is not None and t.type != 'CDATA':
             t.doccomments = self._doccomments