[Python-checkins] r69045 - in python/branches/py3k-issue1717: Lib/test/test_parser.py Modules/parsermodule.c
mark.dickinson
python-checkins at python.org
Wed Jan 28 12:41:14 CET 2009
Author: mark.dickinson
Date: Wed Jan 28 12:41:13 2009
New Revision: 69045
Log:
Put (rich) comparisons back in for parser module, and add tests
for those comparisons.
(The parser module docs say that comparisons between ST objects
should be supported.)
Modified:
python/branches/py3k-issue1717/Lib/test/test_parser.py
python/branches/py3k-issue1717/Modules/parsermodule.c
Modified: python/branches/py3k-issue1717/Lib/test/test_parser.py
==============================================================================
--- python/branches/py3k-issue1717/Lib/test/test_parser.py (original)
+++ python/branches/py3k-issue1717/Lib/test/test_parser.py Wed Jan 28 12:41:13 2009
@@ -2,6 +2,7 @@
import os
import unittest
import sys
+import operator
from test import support
#
@@ -496,12 +497,81 @@
file=sys.stderr)
self.assertRaises(MemoryError, parser.expr, e)
+class STObjectTestCase(unittest.TestCase):
+ """Test operations on ST objects themselves"""
+
+ def test_comparisons(self):
+ # ST objects should support order and equality comparisons
+ st1 = parser.expr('2 + 3')
+ st2 = parser.suite('x = 2; y = x + 3')
+ st3 = parser.expr('list(x**3 for x in range(20))')
+ st1_copy = parser.expr('2 + 3')
+ st2_copy = parser.suite('x = 2; y = x + 3')
+ st3_copy = parser.expr('list(x**3 for x in range(20))')
+
+ # exercise fast path for object identity
+ self.assertEquals(st1 == st1, True)
+ self.assertEquals(st2 == st2, True)
+ self.assertEquals(st3 == st3, True)
+ # slow path equality
+ self.assertEqual(st1, st1_copy)
+ self.assertEqual(st2, st2_copy)
+ self.assertEqual(st3, st3_copy)
+ self.assertEquals(st1 == st2, False)
+ self.assertEquals(st1 == st3, False)
+ self.assertEquals(st2 == st3, False)
+ self.assertEquals(st1 != st1, False)
+ self.assertEquals(st2 != st2, False)
+ self.assertEquals(st3 != st3, False)
+ self.assertEquals(st1 != st1_copy, False)
+ self.assertEquals(st2 != st2_copy, False)
+ self.assertEquals(st3 != st3_copy, False)
+ self.assertEquals(st2 != st1, True)
+ self.assertEquals(st1 != st3, True)
+ self.assertEquals(st3 != st2, True)
+ # we don't particularly care what the ordering is; just that
+ # it's usable and self-consistent
+ self.assertEquals(st1 < st2, not (st2 <= st1))
+ self.assertEquals(st1 < st3, not (st3 <= st1))
+ self.assertEquals(st2 < st3, not (st3 <= st2))
+ self.assertEquals(st1 < st2, st2 > st1)
+ self.assertEquals(st1 < st3, st3 > st1)
+ self.assertEquals(st2 < st3, st3 > st2)
+ self.assertEquals(st1 <= st2, st2 >= st1)
+ self.assertEquals(st3 <= st1, st1 >= st3)
+ self.assertEquals(st2 <= st3, st3 >= st2)
+ # transitivity
+ bottom = min(st1, st2, st3)
+ top = max(st1, st2, st3)
+ mid = sorted([st1, st2, st3])[1]
+ self.assert_(bottom < mid)
+ self.assert_(bottom < top)
+ self.assert_(mid < top)
+ self.assert_(bottom <= mid)
+ self.assert_(bottom <= top)
+ self.assert_(mid <= top)
+ self.assert_(bottom <= bottom)
+ self.assert_(mid <= mid)
+ self.assert_(top <= top)
+ # interaction with other types
+ self.assertEquals(st1 == 1588.602459, False)
+ self.assertEquals('spanish armada' != st2, True)
+ self.assertRaises(TypeError, operator.ge, st3, None)
+ self.assertRaises(TypeError, operator.le, False, st1)
+ self.assertRaises(TypeError, operator.lt, st1, 1815)
+ self.assertRaises(TypeError, operator.gt, b'waterloo', st2)
+
+
+ # XXX tests for pickling and unpickling of ST objects should go here
+
+
def test_main():
support.run_unittest(
RoundtripLegalSyntaxTestCase,
IllegalSyntaxTestCase,
CompileTestCase,
ParserStackLimitTestCase,
+ STObjectTestCase,
)
Modified: python/branches/py3k-issue1717/Modules/parsermodule.c
==============================================================================
--- python/branches/py3k-issue1717/Modules/parsermodule.c (original)
+++ python/branches/py3k-issue1717/Modules/parsermodule.c Wed Jan 28 12:41:13 2009
@@ -169,6 +169,7 @@
static void parser_free(PyST_Object *st);
+static PyObject* parser_richcompare(PyObject *left, PyObject *right, int op);
static PyObject* parser_compilest(PyST_Object *, PyObject *, PyObject *);
static PyObject* parser_isexpr(PyST_Object *, PyObject *, PyObject *);
static PyObject* parser_issuite(PyST_Object *, PyObject *, PyObject *);
@@ -222,7 +223,7 @@
"Intermediate representation of a Python parse tree.",
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ parser_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
@@ -230,6 +231,102 @@
}; /* PyST_Type */
+/* PyST_Type isn't subclassable, so just check ob_type */
+#define PyST_Object_Check(v) ((v)->ob_type == &PyST_Type)
+
+static int
+parser_compare_nodes(node *left, node *right)
+{
+ int j;
+
+ if (TYPE(left) < TYPE(right))
+ return (-1);
+
+ if (TYPE(right) < TYPE(left))
+ return (1);
+
+ if (ISTERMINAL(TYPE(left)))
+ return (strcmp(STR(left), STR(right)));
+
+ if (NCH(left) < NCH(right))
+ return (-1);
+
+ if (NCH(right) < NCH(left))
+ return (1);
+
+ for (j = 0; j < NCH(left); ++j) {
+ int v = parser_compare_nodes(CHILD(left, j), CHILD(right, j));
+
+ if (v != 0)
+ return (v);
+ }
+ return (0);
+}
+
+/* parser_richcompare(PyObject* left, PyObject* right, int op)
+ *
+ * Comparison function used by the Python operators ==, !=, <, >, <=, >=
+ * This really just wraps a call to parser_compare_nodes() with some easy
+ * checks and protection code.
+ *
+ */
+
+#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
+
+static PyObject *
+parser_richcompare(PyObject *left, PyObject *right, int op)
+{
+ int result;
+ PyObject *v;
+
+ /* neither argument should be NULL, unless something's gone wrong */
+ if (left == NULL || right == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ /* both arguments should be instances of PyST_Object */
+ if (!PyST_Object_Check(left) || !PyST_Object_Check(right)) {
+ v = Py_NotImplemented;
+ goto finished;
+ }
+
+ if (left == right)
+ /* if arguments are identical, they're equal */
+ result = 0;
+ else
+ result = parser_compare_nodes(((PyST_Object *)left)->st_node,
+ ((PyST_Object *)right)->st_node);
+
+ /* Convert return value to a Boolean */
+ switch (op) {
+ case Py_EQ:
+ v = TEST_COND(result == 0);
+ break;
+ case Py_NE:
+ v = TEST_COND(result != 0);
+ break;
+ case Py_LE:
+ v = TEST_COND(result <= 0);
+ break;
+ case Py_GE:
+ v = TEST_COND(result >= 0);
+ break;
+ case Py_LT:
+ v = TEST_COND(result < 0);
+ break;
+ case Py_GT:
+ v = TEST_COND(result > 0);
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+ finished:
+ Py_INCREF(v);
+ return v;
+}
+
/* parser_newstobject(node* st)
*
* Allocates a new Python object representing an ST. This is simply the
More information about the Python-checkins
mailing list