summaryrefslogtreecommitdiffstats
path: root/lib2to3c
diff options
context:
space:
mode:
Diffstat (limited to 'lib2to3c')
-rw-r--r--lib2to3c/RO.cocci5
-rw-r--r--lib2to3c/__init__.py71
-rw-r--r--lib2to3c/init-module.cocci78
-rw-r--r--lib2to3c/initmodule.py132
-rw-r--r--lib2to3c/int-to-long.cocci82
-rw-r--r--lib2to3c/ob_type.cocci27
-rw-r--r--lib2to3c/repr.cocci27
-rw-r--r--lib2to3c/typeobject.py77
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()