From: Robert Bradshaw Date: Wed, 10 Feb 2010 09:27:24 +0000 (-0800) Subject: More buffer type analysis deferment. X-Git-Tag: 0.13.beta0~349^2~1 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=ca6c67430b99923c2524340cba600d5d652d7275;p=cython.git More buffer type analysis deferment. --- diff --git a/Cython/Compiler/Buffer.py b/Cython/Compiler/Buffer.py index 98535dee..d7d66e82 100644 --- a/Cython/Compiler/Buffer.py +++ b/Cython/Compiler/Buffer.py @@ -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) diff --git a/Cython/Compiler/Interpreter.py b/Cython/Compiler/Interpreter.py index 05252b07..0acbd923 100644 --- a/Cython/Compiler/Interpreter.py +++ b/Cython/Compiler/Interpreter.py @@ -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) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index ed08e494..93536334 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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): diff --git a/Cython/Compiler/Parsing.pxd b/Cython/Compiler/Parsing.pxd index e80d70a1..2848568a 100644 --- a/Cython/Compiler/Parsing.pxd +++ b/Cython/Compiler/Parsing.pxd @@ -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 diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 34778338..3f545c10 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -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(']') diff --git a/Cython/Compiler/Tests/TestBuffer.py b/Cython/Compiler/Tests/TestBuffer.py index 44caa446..94792360 100644 --- a/Cython/Compiler/Tests/TestBuffer.py +++ b/Cython/Compiler/Tests/TestBuffer.py @@ -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") diff --git a/tests/errors/e_bufaccess.pyx b/tests/errors/e_bufaccess.pyx index 916013ab..0281b67b 100644 --- a/tests/errors/e_bufaccess.pyx +++ b/tests/errors/e_bufaccess.pyx @@ -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