Commit ca6c6743 authored by Robert Bradshaw's avatar Robert Bradshaw

More buffer type analysis deferment.

parent c0fb8492
......@@ -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)
......
......@@ -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)
......@@ -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):
......
......@@ -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
......
......@@ -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(']')
......
......@@ -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")
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment