diff options
Diffstat (limited to 'lib2to3c')
-rw-r--r-- | lib2to3c/RO.cocci | 5 | ||||
-rw-r--r-- | lib2to3c/__init__.py | 71 | ||||
-rw-r--r-- | lib2to3c/init-module.cocci | 78 | ||||
-rw-r--r-- | lib2to3c/initmodule.py | 132 | ||||
-rw-r--r-- | lib2to3c/int-to-long.cocci | 82 | ||||
-rw-r--r-- | lib2to3c/ob_type.cocci | 27 | ||||
-rw-r--r-- | lib2to3c/repr.cocci | 27 | ||||
-rw-r--r-- | lib2to3c/typeobject.py | 77 |
8 files changed, 499 insertions, 0 deletions
diff --git a/lib2to3c/RO.cocci b/lib2to3c/RO.cocci new file mode 100644 index 0000000..14e0229 --- /dev/null +++ b/lib2to3c/RO.cocci @@ -0,0 +1,5 @@ +// structmember.h lost the #define alias RO for READONLY; replace accordingly: +@@ +@@ +-RO ++READONLY
\ No newline at end of file diff --git a/lib2to3c/__init__.py b/lib2to3c/__init__.py new file mode 100644 index 0000000..8d545ae --- /dev/null +++ b/lib2to3c/__init__.py @@ -0,0 +1,71 @@ +import os +import tempfile +from subprocess import Popen, PIPE + +class Fix(object): + def transform(self, string): + raise NotImplementedError + +class CoccinelleError(RuntimeError): + def __init__(self, p, args, stderr): + self.p = p + self.args = args + self.stderr = stderr + + def __str__(self): + return ('Return code: %s (args: %s)\n --- start of captured stderr ---\n%s--- enf of captured stderr ---\n' + % (self.p.returncode, repr(self.args), self.stderr)) + +class CocciFix(Fix): + def __init__(self, filename): + self.filename = filename + + def get_script_path(self): + return os.path.join('lib2to3c', self.filename) + + def transform(self, string): + # spatch seems to require the input and output to be actual files, + # rather than stdin/stdout. + + (src_hn, src_path) = tempfile.mkstemp(suffix="-%s.in.c" % self.filename) + #print (src_hn, src_path) + (dst_hn, dst_path) = tempfile.mkstemp(suffix="-%s.out.c" % self.filename) + #print (dst_hn, dst_path) + os.write(src_hn, string) + + args = ['spatch', '-sp_file', self.get_script_path(), src_path, '-o', dst_path] + p = Popen(args, stdout=PIPE, stderr=PIPE) + (stdout, stderr) = p.communicate() + if p.returncode != 0: + raise CoccinelleError(p, args, stderr) + + string = open(dst_path, 'r').read() + os.close(src_hn) + os.close(dst_hn) + + return string + +import unittest +class NonequalStrings(Exception): + def __init__(self, actual_result, exp_result): + self.actual_result = actual_result + self.exp_result = exp_result + + def __str__(self): + from difflib import unified_diff + result = '\n' + for line in unified_diff(self.exp_result.splitlines(), + self.actual_result.splitlines(), + fromfile = 'Expected result', + tofile = 'Actual result', + lineterm=''): + result += line + '\n' + return result + +class FixTest(unittest.TestCase): + '''Subclass of TestCase for verifying that a Fix is working as expected''' + def assertTransformsTo(self, fixer, src, exp_result): + actual_result = fixer.transform(src) + if actual_result != exp_result: + raise NonequalStrings(actual_result, exp_result) + diff --git a/lib2to3c/init-module.cocci b/lib2to3c/init-module.cocci new file mode 100644 index 0000000..ca3bcc9 --- /dev/null +++ b/lib2to3c/init-module.cocci @@ -0,0 +1,78 @@ +@ mod_init_fn @ +type T; +identifier FN; +identifier MOD_VAR; +expression MODULE_NAME, MODULE_METHODS, MODULE_DOC; +@@ +T FN(void) { + ... + MOD_VAR = Py_InitModule3(MODULE_NAME, MODULE_METHODS, MODULE_DOC); + ... +} + + + +@@ +identifier MOD_VAR; +expression MODULE_NAME, MODULE_METHODS, MODULE_DOC; +expression E; +@@ + if (E) { +- return; ++ return MOD_ERROR_VAL; + } + ... + MOD_VAR = Py_InitModule3(MODULE_NAME, MODULE_METHODS, MODULE_DOC); + + +@@ +identifier MOD_VAR; +expression MODULE_NAME, MODULE_METHODS, MODULE_DOC; +expression E; +@@ + MOD_VAR = Py_InitModule3(MODULE_NAME, MODULE_METHODS, MODULE_DOC); + ... + if (E) { +- return; ++ return MOD_ERROR_VAL; + } + + +@@ +type mod_init_fn.T; +identifier mod_init_fn.FN; +identifier mod_init_fn.MOD_VAR; +expression MODULE_NAME, MODULE_METHODS, MODULE_DOC; +expression E; +statement list SL; +@@ ++struct __HASH_IF_PY_MAJOR_VERSION_ge_3; ++static struct PyModuleDef moduledef = { ++ PyModuleDef_HEAD_INIT, ++ MODULE_NAME, /* m_name */ ++ MODULE_DOC, /* m_doc */ ++ 0, /* m_size */ ++ MODULE_METHODS, /* m_methods */ ++ NULL, /* m_reload */ ++ NULL, /* m_traverse */ ++ NULL, /* m_clear */ ++ NULL, /* m_free */ ++}; ++struct __HASH_DEFINE__MOD_ERROR_VAL__NULL; ++struct __HASH_ELSE; ++struct __HASH_DEFINE__MOD_ERROR_VAL__; ++struct __HASH_ENDIF; + + T FN(void) { + ... + ++__HASH_IF_PY_MAJOR_VERSION_ge_3; ++ MOD_VAR = PyModule_Create(&moduledef); ++__HASH_ELSE; + MOD_VAR = Py_InitModule3(MODULE_NAME, MODULE_METHODS, MODULE_DOC); ++__HASH_ENDIF; + + ... + } + + diff --git a/lib2to3c/initmodule.py b/lib2to3c/initmodule.py new file mode 100644 index 0000000..c890a9e --- /dev/null +++ b/lib2to3c/initmodule.py @@ -0,0 +1,132 @@ +from lib2to3c import CocciFix, FixTest +class FixInitModule(CocciFix): + def __init__(self): + CocciFix.__init__(self, 'init-module.cocci') + + def preprocess(self, string): + # FIXME + return string + + def postprocess(self, string): + for (before, after) in [('struct __HASH_IF_PY_MAJOR_VERSION_ge_3;', + '#if PY_MAJOR_VERSION > 3'), + ('struct __HASH_ELSE;', + '#else'), + ('struct __HASH_DEFINE__MOD_ERROR_VAL__NULL;', + '#define MOD_ERROR_VAL NULL'), + ('struct __HASH_DEFINE__MOD_ERROR_VAL__;', + '#define MOD_ERROR_VAL'), + ('struct __HASH_ENDIF;', + '#endif'), + ('__HASH_IF_PY_MAJOR_VERSION_ge_3;', + '#if PY_MAJOR_VERSION > 3'), + ('__HASH_ELSE;', + '#else'), + ('__HASH_ENDIF;', + '#endif'), + ]: + string = string.replace(before, after) + + # etc + return string + + def transform(self, string): + # FIXME: preprocess + string = self.preprocess(string) + #print 'input:', repr(string) + string = CocciFix.transform(self, string) + #print 'output:', repr(string) + string = self.postprocess(string) + return string + +#import unittest +class TestFixups(FixTest): + def setUp(self): + self.fixer = FixInitModule() + + def test_fixups(self): + self.assertTransformsTo(self.fixer, + ''' +PyMODINIT_FUNC +initxx(void) +{ + PyObject *m; + + if (something_that_can_fail() < 0) + return; + + m = Py_InitModule3("xx", xx_methods, module_doc); + if (m == NULL) + return; + + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); +} +''', + ''' +#if PY_MAJOR_VERSION > 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "xx",/* m_name */ + module_doc,/* m_doc */ + 0,/* m_size */ + xx_methods,/* m_methods */ + NULL,/* m_reload */ + NULL,/* m_traverse */ + NULL,/* m_clear */ + NULL,/* m_free */ +}; +#define MOD_ERROR_VAL NULL +#else +#define MOD_ERROR_VAL +#endif +PyMODINIT_FUNC +initxx(void) +{ + PyObject *m; + + if (something_that_can_fail() < 0) + return MOD_ERROR_VAL; + + #if PY_MAJOR_VERSION > 3 + m = PyModule_Create(&moduledef); + #else + m = Py_InitModule3("xx", xx_methods, module_doc); + #endif + if (m == NULL) + return MOD_ERROR_VAL; + + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); +} +''') +# FIXME: this should have a trailing: +''' + #if PY_MAJOR_VERSION > 3 + return m; + #endif +''' +# but I haven't figured out how to get spatch to add that whilst correctly +# handling error paths + +# Some code that isn't handled yet: +# Multiple error-handling paths: +''' +PyMODINIT_FUNC +initxx(void) +{ + PyObject *m; + + if (something_that_can_fail() < 0) + return; + + m = Py_InitModule3("xx", xx_methods, module_doc); + if (m == NULL) + return; + + if (PyType_Ready(&Null_Type) < 0) + return; + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); +} +''' + +if __name__ == '__main__': + unittest.main() diff --git a/lib2to3c/int-to-long.cocci b/lib2to3c/int-to-long.cocci new file mode 100644 index 0000000..110d97d --- /dev/null +++ b/lib2to3c/int-to-long.cocci @@ -0,0 +1,82 @@ +@@ +expression E1; +@@ +-PyInt_AsLong(E1) ++PyLong_AsLong(E1) + +@@ +expression E1; +@@ +-PyInt_Check(E1) ++PyLong_Check(E1) + +@@ +expression E1, E2, E3; +@@ +-PyInt_FromString(E1, E2, E3) ++PyLong_FromString(E1, E2, E3) + +@@ +expression E1, E2, E3; +@@ +-PyInt_FromUnicode(E1, E2, E3) ++PyLong_FromUnicode(E1, E2, E3) + +@@ +expression E1; +@@ +-PyInt_FromLong(E1) ++PyLong_FromLong(E1) + +@@ +expression E1; +@@ +-PyInt_FromSize_t(E1) ++PyLong_FromSize_t(E1) + +@@ +expression E1; +@@ +-PyInt_FromSsize_t(E1) ++PyLong_FromSsize_t(E1) + +@@ +expression E1; +@@ +-PyInt_AsLong(E1) ++PyLong_AsLong(E1) + +@@ +expression E1; +@@ +-PyInt_AsSsize_t(E1) ++PyLong_AsSsize_t(E1) + +@@ +expression E1; +@@ +-PyInt_AsUnsignedLongMask(E1) ++PyLong_AsUnsignedLongMask(E1) + +@@ +expression E1; +@@ +-PyInt_AsUnsignedLongLongMask(E1) ++PyLong_AsUnsignedLongLongMask(E1) + +@@ +expression E1; +@@ +-PyInt_AS_LONG(E1) ++PyLong_AS_LONG(E1) + +@@ +expression E1; +@@ +-PyNumber_Int(E1) ++PyNumber_Long(E1) + +@@ +@@ +-PyInt_Type ++PyLong_Type
\ No newline at end of file diff --git a/lib2to3c/ob_type.cocci b/lib2to3c/ob_type.cocci new file mode 100644 index 0000000..daf6d96 --- /dev/null +++ b/lib2to3c/ob_type.cocci @@ -0,0 +1,27 @@ +// Convert non-PyObject* deferences of "ob_type" to use Py_TYPE macro instead +@@ +PyObject *py_obj_ptr; +type T; +T non_py_obj_ptr; +@@ +( + py_obj_ptr->ob_type +| +- non_py_obj_ptr->ob_type ++ Py_TYPE(non_py_obj_ptr) +) + +@@ +identifier F; // FIXME: must be an initial field of a struct +type T; +T non_py_obj_ptr; +@@ +- non_py_obj_ptr->F.ob_type ++ Py_TYPE(non_py_obj_ptr) + +@@ +PyTypeObject typeobj; +@@ +- typeobj.ob_type ++ Py_TYPE(&typeobj) + diff --git a/lib2to3c/repr.cocci b/lib2to3c/repr.cocci new file mode 100644 index 0000000..dfa1ef4 --- /dev/null +++ b/lib2to3c/repr.cocci @@ -0,0 +1,27 @@ +// tp_repr functions should return unicode in py3k +// FIXME: need to restrict to just tp_repr functions: +@@ +type T; +function FN_repr; +expression E; +@@ +PyObject * +FN_repr(T *self) +{ + ... +- return PyString_FromString(E); ++ return PyUnicode_FromString(E); +} + +@@ +type T; +function FN_repr; +expression E1, E2; +@@ +PyObject * +FN_repr(T *self) +{ + ... +- return PyString_FromFormat(E1, E2); ++ return PyUnicode_FromFormat(E1, E2); +} diff --git a/lib2to3c/typeobject.py b/lib2to3c/typeobject.py new file mode 100644 index 0000000..56a9744 --- /dev/null +++ b/lib2to3c/typeobject.py @@ -0,0 +1,77 @@ +import sys +import re + +# I wasn't able to express this refactoring in SmPLs; the implied comma embedded +# in the _HEAD_INIT macros seems to be too much for spatch to reasonably deal +# with. + +# So I expressed this one as a regex. + +# Whitespace patterns: +req_ws = r'\s+' +opt_ws = r'\s*' +c_identifier = r'([_A-Za-z][_0-9A-Za-z]*)' + +pat = ('.*' + r'PyTypeObject' + req_ws + + c_identifier + opt_ws + + r'=' + opt_ws + r'\{' + opt_ws + + r'(PyObject_HEAD_INIT\((.*)\)' + opt_ws + + r'([0-9]+)' + opt_ws + r',).*' + ) + +def fixup_typeobject_initializers(content): + while True: + m = re.match(pat, content, re.DOTALL) + if m: + if False: + print m.groups() + print m.group(2) + print m.group(3) + print m.group(4) + print m.span(2) + content = (content[:m.start(2)] + + 'PyVarObject_HEAD_INIT(%s, %s)' % (m.group(3),m.group(4)) + + content[m.end(2):]) + else: + return content + +from lib2to3c import Fix, FixTest +class FixTypeobjectInitializers(Fix): + def transform(self, string): + return fixup_typeobject_initializers(string) + +import unittest +class TestFixups(FixTest): + def setUp(self): + self.fixer = FixTypeobjectInitializers() + + def test_fixups(self): + self.assertTransformsTo(self.fixer, + ''' +PyTypeObject DBusPyIntBase_Type = { + PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) + 0, + "_dbus_bindings._IntBase", +''', + ''' +PyTypeObject DBusPyIntBase_Type = { + PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) + "_dbus_bindings._IntBase", +''') + + def test_fixup_with_comment(self): + self.assertTransformsTo(self.fixer, + ''' +PyTypeObject PyFortran_Type = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "fortran", /*tp_name*/ +''', + ''' +PyTypeObject PyFortran_Type = { + PyVarObject_HEAD_INIT(0, 0) /*ob_size*/ + "fortran", /*tp_name*/ +''') + +if __name__ == '__main__': + unittest.main() |