More buffer type analysis deferment.
authorRobert Bradshaw <robertwb@math.washington.edu>
Wed, 10 Feb 2010 09:27:24 +0000 (01:27 -0800)
committerRobert Bradshaw <robertwb@math.washington.edu>
Wed, 10 Feb 2010 09:27:24 +0000 (01:27 -0800)
Cython/Compiler/Buffer.py
Cython/Compiler/Interpreter.py
Cython/Compiler/Nodes.py
Cython/Compiler/Parsing.pxd
Cython/Compiler/Parsing.py
Cython/Compiler/Tests/TestBuffer.py
tests/errors/e_bufaccess.pyx

index 98535deee2d61316f5ba53ec7cb254e5937a6dde..d7d66e8277f9f871a4cba9d620fd2028822ed49b 100644 (file)
@@ -137,7 +137,7 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee
     if defaults is None:
         defaults = buffer_defaults
     
-    posargs, dictargs = Interpreter.interpret_compiletime_options(posargs, dictargs, type_env=env)
+    posargs, dictargs = Interpreter.interpret_compiletime_options(posargs, dictargs, type_env=env, type_args = (0,'dtype'))
     
     if len(posargs) > buffer_positional_options_count:
         raise CompileError(posargs[-1][1], ERR_BUF_TOO_MANY)
index 05252b079cfff2e4b013d5b3ac43a54ea61fdf43..0acbd9231740cd2d59a3a4210924ce74ebe3e769 100644 (file)
@@ -17,7 +17,7 @@ class EmptyScope(object):
     
 empty_scope = EmptyScope()
 
-def interpret_compiletime_options(optlist, optdict, type_env=None):
+def interpret_compiletime_options(optlist, optdict, type_env=None, type_args=()):
     """
     Tries to interpret a list of compile time option nodes.
     The result will be a tuple (optlist, optdict) but where
@@ -34,21 +34,21 @@ def interpret_compiletime_options(optlist, optdict, type_env=None):
     A CompileError will be raised if there are problems.
     """
 
-    def interpret(node):
-        if isinstance(node, CBaseTypeNode):
+    def interpret(node, ix):
+        if ix in type_args:
             if type_env:
-                return (node.analyse(type_env), node.pos)
+                return (node.analyse_as_type(type_env), node.pos)
             else:
                 raise CompileError(node.pos, "Type not allowed here.")
         else:
             return (node.compile_time_value(empty_scope), node.pos)
      
     if optlist:
-        optlist = [interpret(x) for x in optlist]
+        optlist = [interpret(x, ix) for ix, x in enumerate(optlist)]
     if optdict:
         assert isinstance(optdict, DictNode)
         new_optdict = {}
         for item in optdict.key_value_pairs:
-            new_optdict[item.key.value] = interpret(item.value)
+            new_optdict[item.key.value] = interpret(item.value, item.key.value)
         optdict = new_optdict
     return (optlist, new_optdict)
index ed08e494264d035bd61e6ca44be5a82d592ef853..93536334e808f59c57228d1eaa5105badf036a91 100644 (file)
@@ -791,6 +791,7 @@ class TemplatedTypeNode(CBaseTypeNode):
         if base_type.is_error: return base_type
         
         if base_type.is_cpp_class:
+            # Templated class
             if len(self.keyword_args.key_value_pairs) != 0:
                 error(self.pos, "c++ templates cannot take keyword arguments");
                 self.type = PyrexTypes.error_type
@@ -800,8 +801,8 @@ class TemplatedTypeNode(CBaseTypeNode):
                     template_types.append(template_node.analyse_as_type(env))
                 self.type = base_type.specialize_here(self.pos, template_types)
         
-        else:
-        
+        elif base_type.is_pyobject:
+            # Buffer
             import Buffer
 
             options = Buffer.analyse_buffer_options(
@@ -817,6 +818,24 @@ class TemplatedTypeNode(CBaseTypeNode):
                                  for name, value in options.iteritems() ])
 
             self.type = PyrexTypes.BufferType(base_type, **options)
+        
+        else:
+            # Array
+            empty_declarator = CNameDeclaratorNode(self.pos, name="")
+            if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs:
+                error(self.pos, "invalid array declaration")
+                self.type = PyrexTypes.error_type
+            else:
+                # It would be nice to merge this class with CArrayDeclaratorNode, 
+                # but arrays are part of the declaration, not the type...
+                if not self.positional_args:
+                    dimension = None
+                else:
+                    dimension = self.positional_args[0]
+                self.type = CArrayDeclaratorNode(self.pos, 
+                    base = empty_declarator, 
+                    dimension = dimension).analyse(base_type, env)[1]
+        
         return self.type
 
 class CComplexBaseTypeNode(CBaseTypeNode):
index e80d70a1c5dc5c9c3e97d925ab94d5b8ffd43230..2848568a44136f7d36dae031fb0bf86e018608ff 100644 (file)
@@ -100,13 +100,13 @@ cpdef p_IF_statement(PyrexScanner s, ctx)
 cpdef p_statement(PyrexScanner s, ctx, bint first_statement = *)
 cpdef p_statement_list(PyrexScanner s, ctx, bint first_statement = *)
 cpdef p_suite(PyrexScanner s, ctx = *, bint with_doc = *, bint with_pseudo_doc = *)
-cpdef p_positional_and_keyword_args(PyrexScanner s, end_sy_set, type_positions= *, type_keywords= * )
+cpdef p_positional_and_keyword_args(PyrexScanner s, end_sy_set, templates = *)
 
 cpdef p_c_base_type(PyrexScanner s, bint self_flag = *, bint nonempty = *, templates = *)
 cpdef p_calling_convention(PyrexScanner s)
 cpdef p_c_complex_base_type(PyrexScanner s)
 cpdef p_c_simple_base_type(PyrexScanner s, bint self_flag, bint nonempty, templates = *)
-cpdef p_buffer_or_template(PyrexScanner s, base_type_node)
+cpdef p_buffer_or_template(PyrexScanner s, base_type_node, templates)
 cpdef bint looking_at_name(PyrexScanner s) except -2
 cpdef bint looking_at_expr(PyrexScanner s) except -2
 cpdef bint looking_at_base_type(PyrexScanner s) except -2
index 34778338479b11c0b3044392be8e7f26e1b897c2..3f545c10fb7fc5a89bd92cc47c93f6d87dd0711a 100644 (file)
@@ -1723,18 +1723,12 @@ def p_suite(s, ctx = Ctx(), with_doc = 0, with_pseudo_doc = 0):
     else:
         return body
 
-def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keywords=()):
+def p_positional_and_keyword_args(s, end_sy_set, templates = None):
     """
     Parses positional and keyword arguments. end_sy_set
     should contain any s.sy that terminate the argument list.
     Argument expansion (* and **) are not allowed.
 
-    type_positions and type_keywords specifies which argument
-    positions and/or names which should be interpreted as
-    types. Other arguments will be treated as expressions.
-    A value of None indicates all positions/keywords 
-    (respectively) will be treated as types. 
-
     Returns: (positional_args, keyword_args)
     """
     positional_args = []
@@ -1745,34 +1739,33 @@ def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keyword
         if s.sy == '*' or s.sy == '**':
             s.error('Argument expansion not allowed here.')
 
-        was_keyword = False
         parsed_type = False
         if s.sy == 'IDENT' and s.peek()[0] == '=':
             ident = s.systring
             s.next() # s.sy is '='
             s.next()
-            if type_keywords is None or ident in type_keywords:
-                base_type = p_c_base_type(s)
+            if looking_at_expr(s):
+                arg = p_simple_expr(s)
+            else:
+                base_type = p_c_base_type(s, templates = templates)
                 declarator = p_c_declarator(s, empty = 1)
                 arg = Nodes.CComplexBaseTypeNode(base_type.pos, 
                     base_type = base_type, declarator = declarator)
                 parsed_type = True
-            else:
-                arg = p_simple_expr(s)
             keyword_node = ExprNodes.IdentifierStringNode(
                 arg.pos, value = EncodedString(ident))
             keyword_args.append((keyword_node, arg))
             was_keyword = True
                 
         else:
-            if type_positions is None or pos_idx in type_positions:
-                base_type = p_c_base_type(s)
+            if looking_at_expr(s):
+                arg = p_simple_expr(s)
+            else:
+                base_type = p_c_base_type(s, templates = templates)
                 declarator = p_c_declarator(s, empty = 1)
                 arg = Nodes.CComplexBaseTypeNode(base_type.pos, 
                     base_type = base_type, declarator = declarator)
                 parsed_type = True
-            else:
-                arg = p_simple_expr(s)
             positional_args.append(arg)
             pos_idx += 1
             if len(keyword_args) > 0:
@@ -1782,9 +1775,7 @@ def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keyword
         if s.sy != ',':
             if s.sy not in end_sy_set:
                 if parsed_type:
-                    s.error("Expected: type")
-                else:
-                    s.error("Expected: expression")
+                    s.error("Unmatched %s" % " or ".join(end_sy_set))
             break
         s.next()
     return positional_args, keyword_args
@@ -1876,25 +1867,19 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
         is_self_arg = self_flag, templates = templates)
 
 
-    # Treat trailing [] on type as buffer access if it appears in a context
-    # where declarator names are required (so that it cannot mean int[] or
-    # sizeof(int[SIZE]))...
-    #
-    # (This means that buffers cannot occur where there can be empty declarators,
-    # which is an ok restriction to make.)
-    if nonempty and s.sy == '[':
-        return p_buffer_or_template(s, type_node)
+    if s.sy == '[':
+        return p_buffer_or_template(s, type_node, templates)
     else:
         return type_node
 
-def p_buffer_or_template(s, base_type_node):
+def p_buffer_or_template(s, base_type_node, templates):
     # s.sy == '['
     pos = s.position()
     s.next()
     # Note that buffer_positional_options_count=1, so the only positional argument is dtype. 
     # For templated types, all parameters are types. 
     positional_args, keyword_args = (
-        p_positional_and_keyword_args(s, (']',), None, ('dtype',))
+        p_positional_and_keyword_args(s, (']',), templates)
     )
     s.expect(']')
 
index 44caa446b2e14b4e7debeca1241bf86d8a1d53ae..94792360c75844bf1e8b26a4066de14d15020394 100644 (file)
@@ -32,10 +32,6 @@ class TestBufferParsing(CythonTest):
     def test_type_keyword(self):
         self.parse(u"cdef object[foo=foo, dtype=short unsigned int] x")
 
-    def test_notype_as_expr1(self):
-        self.not_parseable("Expected: expression",
-                           u"cdef object[foo2=short unsigned int] x")
-
     def test_pos_after_key(self):
         self.not_parseable("Non-keyword arg following keyword arg",
                            u"cdef object[foo=1, 2] x")
index 916013abaf93495aa7334e6a5b6d51b1a65a410e..0281b67b675f1fb1dc6cabdce23eb37f49bd7200 100644 (file)
@@ -14,7 +14,7 @@ def f():
 _ERRORS = u"""
 1:17: Buffer types only allowed as function local variables
 3:21: Buffer types only allowed as function local variables
-6:27: "fakeoption" is not a buffer option
+6:31: "fakeoption" is not a buffer option
 """
 #TODO:
 #7:22: "ndim" must be non-negative