Commit 1489a615 authored by Mark Florisson's avatar Mark Florisson

Change fused types syntax:

    cdef fused my_fused_type:
        type1
        type2

and

    my_fused_type = cython.fused_type(type1, type2)

in pure mode.
parent 5905117e
...@@ -961,29 +961,39 @@ class FusedTypeNode(CBaseTypeNode): ...@@ -961,29 +961,39 @@ class FusedTypeNode(CBaseTypeNode):
ctypedef cython.fused_type(int, long, long long) integral ctypedef cython.fused_type(int, long, long long) integral
name str name of this fused type
types [CSimpleBaseTypeNode] is the list of types to be fused types [CSimpleBaseTypeNode] is the list of types to be fused
""" """
child_attrs = [] child_attrs = []
def analyse_declarations(self, env):
type = self.analyse(env)
entry = env.declare_typedef(self.name, type, self.pos)
# Omit the typedef declaration that self.declarator would produce
entry.in_cinclude = True
def analyse(self, env): def analyse(self, env):
# Note: this list may still contain multiple of the same entries types = []
types = [type.analyse_as_type(env) for type in self.types] for type_node in self.types:
type = type_node.analyse_as_type(env)
if len(self.types) == 1: if not type:
return types[0] error(type_node.pos, "Not a type")
continue
seen = cython.set() if type in types:
for type_node, type in zip(self.types, types):
if type in seen:
error(type_node.pos, "Type specified multiple times") error(type_node.pos, "Type specified multiple times")
else: elif type.is_fused:
seen.add(type)
if type.is_fused:
error(type_node.pos, "Cannot fuse a fused type") error(type_node.pos, "Cannot fuse a fused type")
else:
types.append(type)
if len(self.types) == 1:
return types[0]
self.types = types return PyrexTypes.FusedType(types, name=self.name)
return PyrexTypes.FusedType(types)
class CVarDefNode(StatNode): class CVarDefNode(StatNode):
...@@ -1226,17 +1236,11 @@ class CTypeDefNode(StatNode): ...@@ -1226,17 +1236,11 @@ class CTypeDefNode(StatNode):
entry = env.declare_typedef(name, type, self.pos, entry = env.declare_typedef(name, type, self.pos,
cname = cname, visibility = self.visibility, api = self.api) cname = cname, visibility = self.visibility, api = self.api)
if self.in_pxd and not env.in_cinclude: if type.is_fused:
entry.defined_in_pxd = 1
if base.is_fused:
# Omit the typedef declaration that self.declarator would produce
entry.in_cinclude = True entry.in_cinclude = True
if self.visibility == 'public' or self.api: if self.in_pxd and not env.in_cinclude:
error(self.pos, "Fused types cannot be public or api") entry.defined_in_pxd = 1
base.name = name
def analyse_expressions(self, env): def analyse_expressions(self, env):
pass pass
...@@ -4079,20 +4083,6 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -4079,20 +4083,6 @@ class SingleAssignmentNode(AssignmentNode):
error(self.rhs.pos, "Can only declare one type at a time.") error(self.rhs.pos, "Can only declare one type at a time.")
return return
# See if we're dealing with this:
# dtype = cython.typedef(cython.fused_type(...))
if isinstance(args[0], ExprNodes.CallNode):
nested_func_name = args[0].function.as_cython_attribute()
if nested_func_name == u'fused_type':
nested_args, nested_kwds = args[0].explicit_args_kwds()
if nested_kwds is not None:
error(self.rhs.pos,
"fused_type does not take keyword arguments")
args[0] = FusedTypeNode(self.rhs.pos,
types=nested_args)
args[0].name = self.lhs.name
type = args[0].analyse_as_type(env) type = args[0].analyse_as_type(env)
if type is None: if type is None:
error(args[0].pos, "Unknown type") error(args[0].pos, "Unknown type")
...@@ -4141,6 +4131,17 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -4141,6 +4131,17 @@ class SingleAssignmentNode(AssignmentNode):
for member, type, pos in members: for member, type, pos in members:
scope.declare_var(member, type, pos) scope.declare_var(member, type, pos)
elif func_name == 'fused_type':
# dtype = cython.fused_type(...)
self.declaration_only = True
if kwds:
error(self.rhs.function.pos,
"fused_type does not take keyword arguments")
fusednode = FusedTypeNode(self.rhs.pos,
name = self.lhs.name, types=args)
fusednode.analyse_declarations(env)
if self.declaration_only: if self.declaration_only:
return return
else: else:
......
...@@ -959,35 +959,6 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -959,35 +959,6 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return self.visit_with_directives(node.body, directive_dict) return self.visit_with_directives(node.body, directive_dict)
return self.visit_Node(node) return self.visit_Node(node)
def visit_CTypeDefNode(self, node):
"Don't skip ctypedefs"
self.visitchildren(node)
return node
def visit_FusedTypeNode(self, node):
"""
See if a function call expression in a ctypedef is actually
cython.fused_type()
"""
def err():
error(node.pos, "Can only fuse types with cython.fused_type()")
if len(node.funcname) == 1:
fused_type, = node.funcname
else:
cython_module, fused_type = node.funcname
wrong_module = cython_module not in self.cython_module_names
if wrong_module or fused_type != u'fused_type':
err()
return node
if not self.directive_names.get(fused_type):
err()
return node
class ParallelRangeTransform(CythonTransform, SkipDeclarations): class ParallelRangeTransform(CythonTransform, SkipDeclarations):
""" """
......
...@@ -2119,6 +2119,8 @@ sign_and_longness_words = ("short", "long", "signed", "unsigned") ...@@ -2119,6 +2119,8 @@ sign_and_longness_words = ("short", "long", "signed", "unsigned")
base_type_start_words = \ base_type_start_words = \
basic_c_type_names + sign_and_longness_words + tuple(special_basic_c_types) basic_c_type_names + sign_and_longness_words + tuple(special_basic_c_types)
struct_enum_union = ("struct", "union", "enum", "packed")
def p_sign_and_longness(s): def p_sign_and_longness(s):
signed = 1 signed = 1
longness = 0 longness = 0
...@@ -2425,15 +2427,14 @@ def p_cdef_statement(s, ctx): ...@@ -2425,15 +2427,14 @@ def p_cdef_statement(s, ctx):
if ctx.visibility != 'extern': if ctx.visibility != 'extern':
error(pos, "C++ classes need to be declared extern") error(pos, "C++ classes need to be declared extern")
return p_cpp_class_definition(s, pos, ctx) return p_cpp_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring in ("struct", "union", "enum", "packed"): elif s.sy == 'IDENT' and s.systring in struct_enum_union:
if ctx.level not in ('module', 'module_pxd'): if ctx.level not in ('module', 'module_pxd'):
error(pos, "C struct/union/enum definition not allowed here") error(pos, "C struct/union/enum definition not allowed here")
if ctx.overridable: if ctx.overridable:
error(pos, "C struct/union/enum cannot be declared cpdef") error(pos, "C struct/union/enum cannot be declared cpdef")
if s.systring == "enum": return p_struct_enum(s, pos, ctx)
return p_c_enum_definition(s, pos, ctx) elif s.sy == 'IDENT' and s.systring == 'fused':
else: return p_fused_definition(s, pos, ctx)
return p_c_struct_or_union_definition(s, pos, ctx)
else: else:
return p_c_func_or_var_declaration(s, pos, ctx) return p_c_func_or_var_declaration(s, pos, ctx)
...@@ -2550,6 +2551,46 @@ def p_c_struct_or_union_definition(s, pos, ctx): ...@@ -2550,6 +2551,46 @@ def p_c_struct_or_union_definition(s, pos, ctx):
typedef_flag = ctx.typedef_flag, visibility = ctx.visibility, typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed) api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
def p_fused_definition(s, pos, ctx):
"""
c(type)def fused my_fused_type:
...
"""
# s.systring == 'fused'
if ctx.level not in ('module', 'module_pxd'):
error(pos, "Fused type definition not allowed here")
s.next()
name = p_ident(s)
s.expect(":")
s.expect_newline()
s.expect_indent()
types = []
while s.sy != 'DEDENT':
if s.sy != 'pass':
#types.append(p_c_declarator(s))
types.append(p_c_base_type(s)) #, nonempty=1))
else:
s.next()
s.expect_newline()
s.expect_dedent()
if not types:
error(pos, "Need at least one type")
return Nodes.FusedTypeNode(pos, name=name, types=types)
def p_struct_enum(s, pos, ctx):
if s.systring == 'enum':
return p_c_enum_definition(s, pos, ctx)
else:
return p_c_struct_or_union_definition(s, pos, ctx)
def p_visibility(s, prev_visibility): def p_visibility(s, prev_visibility):
pos = s.position() pos = s.position()
visibility = prev_visibility visibility = prev_visibility
...@@ -2609,23 +2650,23 @@ def p_c_func_or_var_declaration(s, pos, ctx): ...@@ -2609,23 +2650,23 @@ def p_c_func_or_var_declaration(s, pos, ctx):
overridable = ctx.overridable) overridable = ctx.overridable)
return result return result
def p_typelist(s): #def p_typelist(s):
""" # """
parse a list of basic c types as part of a function call, like # parse a list of basic c types as part of a function call, like
cython.fused_type(int, long, double) # cython.fused_type(int, long, double)
""" # """
types = [] # types = []
pos = s.position() # pos = s.position()
#
while s.sy == 'IDENT': # while s.sy == 'IDENT':
types.append(p_c_base_type(s)) # types.append(p_c_base_type(s))
if s.sy != ',': # if s.sy != ',':
if s.sy != ')': # if s.sy != ')':
s.expect(',') # s.expect(',')
break # break
s.next() # s.next()
#
return Nodes.FusedTypeNode(pos, types=types) # return Nodes.FusedTypeNode(pos, types=types)
def p_ctypedef_statement(s, ctx): def p_ctypedef_statement(s, ctx):
# s.sy == 'ctypedef' # s.sy == 'ctypedef'
...@@ -2638,30 +2679,10 @@ def p_ctypedef_statement(s, ctx): ...@@ -2638,30 +2679,10 @@ def p_ctypedef_statement(s, ctx):
ctx.api = 1 ctx.api = 1
if s.sy == 'class': if s.sy == 'class':
return p_c_class_definition(s, pos, ctx) return p_c_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring in ('packed', 'struct', 'union', 'enum'): elif s.sy == 'IDENT' and s.systring in struct_enum_union:
if s.systring == 'enum': return p_struct_enum(s, pos, ctx)
return p_c_enum_definition(s, pos, ctx) elif s.sy == 'IDENT' and s.systring == 'fused':
else: return p_fused_definition(s, pos, ctx)
return p_c_struct_or_union_definition(s, pos, ctx)
elif looking_at_call(s):
# ctypedef cython.fused_types(int, long) integral
if s.sy == 'IDENT':
funcname = [s.systring]
s.next()
if s.systring == u'.':
s.next()
funcname.append(s.systring)
s.expect('IDENT')
s.expect('(')
base_type = p_typelist(s)
s.expect(')')
# Check if funcname equals cython.fused_types in
# InterpretCompilerDirectives
base_type.funcname = funcname
else:
s.error("Syntax error in ctypedef statement")
else: else:
base_type = p_c_base_type(s, nonempty = 1) base_type = p_c_base_type(s, nonempty = 1)
if base_type.name is None: if base_type.name is None:
......
...@@ -2874,11 +2874,10 @@ def best_match(args, functions, pos=None, env=None): ...@@ -2874,11 +2874,10 @@ def best_match(args, functions, pos=None, env=None):
if assignable: if assignable:
if src_type == dst_type or dst_type.same_as(src_type): if src_type == dst_type or dst_type.same_as(src_type):
pass # score 0 pass # score 0
elif is_promotion(src_type, dst_type):
score[3] += 1
elif ((src_type.is_int and dst_type.is_int) or elif ((src_type.is_int and dst_type.is_int) or
(src_type.is_float and dst_type.is_float)): (src_type.is_float and dst_type.is_float)):
score[2] += 1 score[2] += abs(dst_type.rank + (not dst_type.signed) -
(src_type.rank + (not src_type.signed)))
elif not src_type.is_pyobject: elif not src_type.is_pyobject:
score[1] += 1 score[1] += 1
else: else:
......
# mode: error
cdef fused my_fused_type: int a; char b
_ERRORS = u"""
fused_syntax.pyx:3:26: Expected a newline
"""
# mode: error
cimport cython
ctypedef cython.fused_type(int, float) fused_t
_ERRORS = u"""
fused_syntax_ctypedef.pyx:5:39: Syntax error in ctypedef statement
"""
...@@ -4,19 +4,19 @@ cimport cython ...@@ -4,19 +4,19 @@ cimport cython
from cython import fused_type from cython import fused_type
# This is all invalid # This is all invalid
ctypedef foo(int) dtype1 # ctypedef foo(int) dtype1
ctypedef foo.bar(float) dtype2 # ctypedef foo.bar(float) dtype2
ctypedef fused_type(foo) dtype3 # ctypedef fused_type(foo) dtype3
dtype4 = cython.typedef(cython.fused_type(int, long, kw=None)) dtype4 = cython.fused_type(int, long, kw=None)
ctypedef public cython.fused_type(int, long) dtype7 # ctypedef public cython.fused_type(int, long) dtype7
ctypedef api cython.fused_type(int, long) dtype8 # ctypedef api cython.fused_type(int, long) dtype8
ctypedef cython.fused_type(short, short int, int) int_t int_t = cython.fused_type(short, short, int)
ctypedef cython.fused_type(int, long) int2_t int2_t = cython.fused_type(int, long)
ctypedef cython.fused_type(int2_t, int) dtype9 dtype9 = cython.fused_type(int2_t, int)
ctypedef cython.fused_type(float, double) floating floating = cython.fused_type(float, double)
cdef func(floating x, int2_t y): cdef func(floating x, int2_t y):
print x, y print x, y
...@@ -29,21 +29,26 @@ func[float, int](x) ...@@ -29,21 +29,26 @@ func[float, int](x)
func[float, int](x, y, y) func[float, int](x, y, y)
func(x, y=y) func(x, y=y)
# This is all valid # This is all valid
ctypedef fused_type(int, long, float) dtype5 dtype5 = fused_type(int, long, float)
ctypedef cython.fused_type(int, long) dtype6 dtype6 = cython.fused_type(int, long)
func[float, int](x, y) func[float, int](x, y)
cdef fused fused1:
int
long long
ctypedef fused fused2:
int
long long
func(x, y) func(x, y)
_ERRORS = u""" _ERRORS = u"""
fused_types.pyx:7:13: Can only fuse types with cython.fused_type() fused_types.pyx:10:15: fused_type does not take keyword arguments
fused_types.pyx:8:17: Can only fuse types with cython.fused_type() fused_types.pyx:15:38: Type specified multiple times
fused_types.pyx:9:20: 'foo' is not a type identifier fused_types.pyx:17:33: Cannot fuse a fused type
fused_types.pyx:10:23: fused_type does not take keyword arguments
fused_types.pyx:12:0: Fused types cannot be public or api
fused_types.pyx:13:0: Fused types cannot be public or api
fused_types.pyx:15:34: Type specified multiple times
fused_types.pyx:17:27: Cannot fuse a fused type
fused_types.pyx:26:4: Not enough types specified to specialize the function, int2_t is still fused fused_types.pyx:26:4: Not enough types specified to specialize the function, int2_t is still fused
fused_types.pyx:27:4: Not enough types specified to specialize the function, int2_t is still fused fused_types.pyx:27:4: Not enough types specified to specialize the function, int2_t is still fused
fused_types.pyx:28:16: Call with wrong number of arguments (expected 2, got 1) fused_types.pyx:28:16: Call with wrong number of arguments (expected 2, got 1)
......
...@@ -5,17 +5,28 @@ import math ...@@ -5,17 +5,28 @@ import math
ctypedef char *string_t ctypedef char *string_t
ctypedef cython.fused_type(int, long, float, string_t) fused_t fused_t = cython.fused_type(int, long, float, string_t)
ctypedef cython.fused_type(int, long) other_t other_t = cython.fused_type(int, long)
ctypedef cython.fused_type(short int, int) base_t base_t = cython.fused_type(short, int)
ctypedef cython.fused_type(float complex, double complex,
int complex, long complex) complex_t # complex_t = cython.fused_type(cython.floatcomplex, cython.doublecomplex)
cdef fused complex_t:
float complex
double complex
ctypedef base_t **base_t_p_p ctypedef base_t **base_t_p_p
# ctypedef cython.fused_type(char, base_t_p_p, fused_t, complex_t) composed_t # ctypedef cython.fused_type(char, base_t_p_p, fused_t, complex_t) composed_t
ctypedef cython.fused_type(char, int, float, string_t, float complex, cdef fused composed_t:
double complex, int complex, long complex, char
cython.p_p_int) composed_t int
float
string_t
cython.pp_int
float complex
double complex
int complex
long complex
cdef func(fused_t a, other_t b): cdef func(fused_t a, other_t b):
......
cimport cython cimport cython
ctypedef cython.fused_type(int, float) unresolved_t unresolved_t = cython.fused_type(int, float)
# mode: run # mode: run
cimport cython cimport cython
#from cython cimport p_double, p_int from cython cimport integral
from cpython cimport Py_INCREF from cpython cimport Py_INCREF
from Cython import Shadow as pure_cython from Cython import Shadow as pure_cython
ctypedef char * string_t ctypedef char * string_t
ctypedef cython.fused_type(float, double) floating # floating = cython.fused_type(float, double) floating
ctypedef cython.fused_type(int, long) integral # integral = cython.fused_type(int, long) integral
ctypedef cython.fused_type(int, long, float, double, string_t) fused_type1 ctypedef cython.floating floating
ctypedef cython.fused_type(string_t) fused_type2 fused_type1 = cython.fused_type(int, long, float, double, string_t)
fused_type2 = cython.fused_type(string_t)
ctypedef fused_type1 *composed_t ctypedef fused_type1 *composed_t
ctypedef cython.fused_type(int, double) other_t other_t = cython.fused_type(int, double)
ctypedef double *p_double ctypedef double *p_double
ctypedef int *p_int ctypedef int *p_int
......
...@@ -30,10 +30,10 @@ cdef public class MyExt [ type MyExtType, object MyExtObject ]: ...@@ -30,10 +30,10 @@ cdef public class MyExt [ type MyExtType, object MyExtObject ]:
cdef unsigned char a cdef unsigned char a
ctypedef char *string_t ctypedef char *string_t
ctypedef cython.fused_type(int, float) simple_t simple_t = cython.fused_type(int, float)
ctypedef cython.fused_type(int, float, string_t) less_simple_t less_simple_t = cython.fused_type(int, float, string_t)
ctypedef cython.fused_type(mystruct_t, myunion_t, MyExt) struct_t struct_t = cython.fused_type(mystruct_t, myunion_t, MyExt)
ctypedef cython.fused_type(str, unicode, bytes) builtin_t builtin_t = cython.fused_type(str, unicode, bytes)
cdef struct_t add_simple(struct_t obj, simple_t simple) cdef struct_t add_simple(struct_t obj, simple_t simple)
cdef less_simple_t add_to_simple(struct_t obj, less_simple_t simple) cdef less_simple_t add_to_simple(struct_t obj, less_simple_t simple)
...@@ -43,7 +43,7 @@ cdef class TestFusedExtMethods(object): ...@@ -43,7 +43,7 @@ cdef class TestFusedExtMethods(object):
cdef cython.floating method(self, cython.integral x, cython.floating y) cdef cython.floating method(self, cython.integral x, cython.floating y)
cpdef cpdef_method(self, cython.integral x, cython.floating y) cpdef cpdef_method(self, cython.integral x, cython.floating y)
ctypedef cython.fused_type(TestFusedExtMethods, object, list) object_t object_t = cython.fused_type(TestFusedExtMethods, object, list)
cpdef public_cpdef(cython.integral x, cython.floating y, object_t z) cpdef public_cpdef(cython.integral x, cython.floating y, object_t z)
......
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