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)
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
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)
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
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(
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):
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
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 = []
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:
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
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(']')
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")
_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