From 7cec62b71f9f33a2757cbb667174ab32e82fa9dd Mon Sep 17 00:00:00 2001
From: Stefan Behnel <stefan_ml@behnel.de>
Date: Wed, 13 Feb 2013 18:54:51 +0100
Subject: [PATCH] support tuples as compile time constants

---
 Cython/Compiler/Parsing.pxd |  1 +
 Cython/Compiler/Parsing.py  | 48 ++++++++++++++++++++++++-------------
 tests/run/ct_DEF.pyx        | 27 ++++++++++++---------
 3 files changed, 49 insertions(+), 27 deletions(-)

diff --git a/Cython/Compiler/Parsing.pxd b/Cython/Compiler/Parsing.pxd
index 2140e290c..4b1757bce 100644
--- a/Cython/Compiler/Parsing.pxd
+++ b/Cython/Compiler/Parsing.pxd
@@ -59,6 +59,7 @@ cdef p_atom(PyrexScanner s)
 @cython.locals(value=unicode)
 cdef p_int_literal(PyrexScanner s)
 cdef p_name(PyrexScanner s, name)
+cdef wrap_compile_time_constant(pos, value)
 cdef p_cat_string_literal(PyrexScanner s)
 cdef p_opt_string_literal(PyrexScanner s, required_type=*)
 cdef bint check_for_non_ascii_characters(unicode string)
diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py
index 7ce75e1ba..43b94d967 100644
--- a/Cython/Compiler/Parsing.py
+++ b/Cython/Compiler/Parsing.py
@@ -678,27 +678,43 @@ def p_int_literal(s):
                              unsigned = unsigned,
                              longness = longness)
 
+
 def p_name(s, name):
     pos = s.position()
     if not s.compile_time_expr and name in s.compile_time_env:
         value = s.compile_time_env.lookup_here(name)
-        rep = repr(value)
-        if isinstance(value, bool):
-            return ExprNodes.BoolNode(pos, value = value)
-        elif isinstance(value, int):
-            return ExprNodes.IntNode(pos, value = rep)
-        elif isinstance(value, long):
-            return ExprNodes.IntNode(pos, value = rep, longness = "L")
-        elif isinstance(value, float):
-            return ExprNodes.FloatNode(pos, value = rep)
-        elif isinstance(value, _unicode):
-            return ExprNodes.UnicodeNode(pos, value = value)
-        elif isinstance(value, _bytes):
-            return ExprNodes.BytesNode(pos, value = value)
+        node = wrap_compile_time_constant(pos, value)
+        if node is not None:
+            return node
+    return ExprNodes.NameNode(pos, name=name)
+
+
+def wrap_compile_time_constant(pos, value):
+    rep = repr(value)
+    if isinstance(value, bool):
+        return ExprNodes.BoolNode(pos, value=value)
+    elif isinstance(value, int):
+        return ExprNodes.IntNode(pos, value=rep)
+    elif isinstance(value, long):
+        return ExprNodes.IntNode(pos, value=rep, longness="L")
+    elif isinstance(value, float):
+        return ExprNodes.FloatNode(pos, value=rep)
+    elif isinstance(value, _unicode):
+        return ExprNodes.UnicodeNode(pos, value=value)
+    elif isinstance(value, _bytes):
+        return ExprNodes.BytesNode(pos, value=value)
+    elif isinstance(value, tuple):
+        args = [wrap_compile_time_constant(pos, arg)
+                for arg in value]
+        if None not in args:
+            return ExprNodes.TupleNode(pos, args=args)
         else:
-            error(pos, "Invalid type for compile-time constant: %s"
-                % value.__class__.__name__)
-    return ExprNodes.NameNode(pos, name = name)
+            # error already reported
+            return None
+    error(pos, "Invalid type for compile-time constant: %s"
+               % value.__class__.__name__)
+    return None
+
 
 def p_cat_string_literal(s):
     # A sequence of one or more adjacent string literals.
diff --git a/tests/run/ct_DEF.pyx b/tests/run/ct_DEF.pyx
index a2f38e189..cef18bac6 100644
--- a/tests/run/ct_DEF.pyx
+++ b/tests/run/ct_DEF.pyx
@@ -8,7 +8,7 @@ if sys.version_info[0] < 3:
     __doc__ = __doc__.replace(u" b'", u" '")
 
 
-DEF TUPLE = (1, 2, u"buckle my shoe")
+DEF TUPLE = (1, 2, "buckle my shoe")
 DEF TRUE_FALSE = (True, False)
 
 DEF CHAR = c'x'
@@ -89,10 +89,21 @@ def s():
     cdef char* s = STR
     return s
 
-# this does not work!
-#def t():
-#    cdef object t = TUPLE
-#    return t
+def constant_tuple():
+    """
+    >>> constant_tuple()
+    (1, 2, 'buckle my shoe')
+    """
+    cdef object t = TUPLE
+    return t
+
+def tuple_indexing():
+    """
+    >>> tuple_indexing()
+    2
+    """
+    cdef int two = INT_TUPLE1[-1]
+    return two
 
 def two():
     """
@@ -102,12 +113,6 @@ def two():
     cdef int two = TWO
     return two
 
-# this doesn't currently work!
-#def two2():
-#    cdef int two
-#    two = INT_TUPLE1[-1]
-#    return two
-
 def five():
     """
     >>> five()
-- 
2.30.9