Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r2930:a772dd1ab09f
Date: 2017-05-09 18:07 +0200
http://bitbucket.org/cffi/cffi/changeset/a772dd1ab09f/

Log:    Try to systematically include the line number

diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -16,6 +16,7 @@
 except ImportError:
     lock = None
 
+CDEF_SOURCE_STRING = "<cdef source string>"
 _r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$",
                         re.DOTALL | re.MULTILINE)
 _r_define  = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)"
@@ -266,7 +267,7 @@
                             ' __dotdotdot__;')
         # this forces pycparser to consider the following in the file
         # called <cdef source string> from line 1
-        csourcelines.append('# 1 "<cdef source string>"')
+        csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,))
         csourcelines.append(csource)
         fullcsource = '\n'.join(csourcelines)
         if lock is not None:
@@ -287,7 +288,7 @@
         # the user gives explicit ``# NUM "FILE"`` directives.
         line = None
         msg = str(e)
-        match = re.match(r"<cdef source string>:(\d+):", msg)
+        match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg)
         if match:
             linenum = int(match.group(1), 10)
             csourcelines = csource.splitlines()
@@ -327,10 +328,12 @@
                 break
         else:
             assert 0
+        current_decl = None
         #
         try:
             self._inside_extern_python = '__cffi_extern_python_stop'
             for decl in iterator:
+                current_decl = decl
                 if isinstance(decl, pycparser.c_ast.Decl):
                     self._parse_decl(decl)
                 elif isinstance(decl, pycparser.c_ast.Typedef):
@@ -354,7 +357,13 @@
                 elif decl.__class__.__name__ == 'Pragma':
                     pass    # skip pragma, only in pycparser 2.15
                 else:
-                    raise CDefError("unrecognized construct", decl)
+                    raise CDefError("unexpected <%s>: this construct is valid "
+                                    "C but not valid in cdef()" %
+                                    decl.__class__.__name__, decl)
+        except CDefError as e:
+            if len(e.args) == 1:
+                e.args = e.args + (current_decl,)
+            raise
         except FFIError as e:
             msg = self._convert_pycparser_error(e, csource)
             if msg:
diff --git a/cffi/error.py b/cffi/error.py
--- a/cffi/error.py
+++ b/cffi/error.py
@@ -5,10 +5,13 @@
 class CDefError(Exception):
     def __str__(self):
         try:
-            line = 'line %d: ' % (self.args[1].coord.line,)
+            current_decl = self.args[1]
+            filename = current_decl.coord.file
+            linenum = current_decl.coord.line
+            prefix = '%s:%d: ' % (filename, linenum)
         except (AttributeError, TypeError, IndexError):
-            line = ''
-        return '%s%s' % (line, self.args[0])
+            prefix = ''
+        return '%s%s' % (prefix, self.args[0])
 
 class VerificationError(Exception):
     """ An error raised when verification fails
diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst
--- a/doc/source/cdef.rst
+++ b/doc/source/cdef.rst
@@ -254,7 +254,7 @@
 string passed to ``cdef()`` and there is an error two lines later, then
 it is reported with an error message that starts with ``foo.h:43:`` (the
 line which is given the number 42 is the line immediately after the
-directive).  *New in version 1.11:*  CFFI automatically puts the line
+directive).  *New in version 1.10.1:*  CFFI automatically puts the line
 ``# 1 "<cdef source string>"`` just before the string you give to
 ``cdef()``.
 
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -3,6 +3,15 @@
 ======================
 
 
+v1.10.1
+=======
+
+* Fixed the line numbers reported in case of ``cdef()`` errors.
+  Also, I just noticed, but pycparser always supported the preprocessor
+  directive ``# 42 "foo.h"`` to mean "from the next line, we're in file
+  foo.h starting from line 42", which it puts in the error messages.
+
+
 v1.10
 =====
 
diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py
--- a/testing/cffi0/test_parsing.py
+++ b/testing/cffi0/test_parsing.py
@@ -228,8 +228,9 @@
     # this checks that we get a sensible error if we try "int foo(...);"
     ffi = FFI()
     e = py.test.raises(CDefError, ffi.cdef, "int foo(...);")
-    assert str(e.value) == \
-           "foo: a function with only '(...)' as argument is not correct C"
+    assert str(e.value) == (
+           "<cdef source string>:1: foo: a function with only '(...)' "
+           "as argument is not correct C")
 
 def test_parse_error():
     ffi = FFI()
@@ -291,7 +292,8 @@
 def test_unknown_argument_type():
     ffi = FFI()
     e = py.test.raises(CDefError, ffi.cdef, "void f(foobarbazzz);")
-    assert str(e.value) == ("f arg 1: unknown type 'foobarbazzz' (if you meant"
+    assert str(e.value) == ("<cdef source string>:1: f arg 1:"
+                            " unknown type 'foobarbazzz' (if you meant"
                             " to use the old C syntax of giving untyped"
                             " arguments, it is not supported)")
 
@@ -449,3 +451,9 @@
             ffi._parser._declarations['extern_python foobar'] !=
             ffi._parser._declarations['function bok'] ==
             ffi._parser._declarations['extern_python bzrrr'])
+
+def test_error_invalid_syntax_for_cdef():
+    ffi = FFI()
+    e = py.test.raises(CDefError, ffi.cdef, 'void foo(void) {}')
+    assert str(e.value) == ('<cdef source string>:1: unexpected <FuncDef>: '
+                            'this construct is valid C but not valid in 
cdef()')
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to