Commits

Armin Rigo  committed 78e101d

Give a better error message than pycparser's default one
on ParseErrors

  • Participants
  • Parent commits ede1d10

Comments (0)

Files changed (2)

File cffi/cparser.py

 
 from . import api, model
-import pycparser, weakref, re
+import pycparser.c_parser, weakref, re
 
 _r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE)
 _r_define  = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)\s+(.*?)$",
         csource, macros = _preprocess(csource)
         csourcelines.append(csource)
         csource = '\n'.join(csourcelines)
-        ast = _get_parser().parse(csource)
+        try:
+            ast = _get_parser().parse(csource)
+        except pycparser.c_parser.ParseError, e:
+            self.convert_pycparser_error(e, csource)
         return ast, macros
 
+    def convert_pycparser_error(self, e, csource):
+        # xxx look for ":NUM:" at the start of str(e) and try to interpret
+        # it as a line number
+        line = None
+        msg = str(e)
+        if msg.startswith(':') and ':' in msg[1:]:
+            linenum = msg[1:msg.find(':',1)]
+            if linenum.isdigit():
+                linenum = int(linenum, 10)
+                csourcelines = csource.splitlines()
+                if 1 <= linenum <= len(csourcelines):
+                    line = csourcelines[linenum-1]
+        if line:
+            msg = 'cannot parse "%s"\n%s' % (line, msg)
+        else:
+            msg = 'parse error\n%s' % (msg,)
+        raise api.CDefError(msg)
+
     def parse(self, csource, override=False):
         prev_override = self._override
         try:

File testing/test_parsing.py

-import py, sys
+import py, sys, re
 from cffi import FFI, FFIError, CDefError, VerificationError
 
 class FakeBackend(object):
     e = py.test.raises(CDefError, ffi.cdef, "int foo(...);")
     assert str(e.value) == \
            "foo: a function with only '(...)' as argument is not correct C"
+
+def test_parse_error():
+    ffi = FFI()
+    e = py.test.raises(CDefError, ffi.cdef, " x y z ")
+    assert re.match(r'cannot parse " x y z "\n:\d+:', str(e.value))