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):
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
"""
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):
# Note: this list may still contain multiple of the same entries
types = [type.analyse_as_type(env) for type in self.types]
types = []
for type_node in self.types:
type = type_node.analyse_as_type(env)
if len(self.types) == 1:
return types[0]
if not type:
error(type_node.pos, "Not a type")
continue
seen = cython.set()
for type_node, type in zip(self.types, types):
if type in seen:
if type in types:
error(type_node.pos, "Type specified multiple times")
elif type.is_fused:
error(type_node.pos, "Cannot fuse a fused type")
else:
seen.add(type)
if type.is_fused:
error(type_node.pos, "Cannot fuse a fused type")
types.append(type)
self.types = types
return PyrexTypes.FusedType(types)
if len(self.types) == 1:
return types[0]
return PyrexTypes.FusedType(types, name=self.name)
class CVarDefNode(StatNode):
......@@ -1226,17 +1236,11 @@ class CTypeDefNode(StatNode):
entry = env.declare_typedef(name, type, self.pos,
cname = cname, visibility = self.visibility, api = self.api)
if self.in_pxd and not env.in_cinclude:
entry.defined_in_pxd = 1
if base.is_fused:
# Omit the typedef declaration that self.declarator would produce
if type.is_fused:
entry.in_cinclude = True
if self.visibility == 'public' or self.api:
error(self.pos, "Fused types cannot be public or api")
base.name = name
if self.in_pxd and not env.in_cinclude:
entry.defined_in_pxd = 1
def analyse_expressions(self, env):
pass
......@@ -4079,20 +4083,6 @@ class SingleAssignmentNode(AssignmentNode):
error(self.rhs.pos, "Can only declare one type at a time.")
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)
if type is None:
error(args[0].pos, "Unknown type")
......@@ -4141,6 +4131,17 @@ class SingleAssignmentNode(AssignmentNode):
for member, type, pos in members:
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:
return
else:
......
......@@ -959,35 +959,6 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return self.visit_with_directives(node.body, directive_dict)
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):
"""
......
......@@ -2119,6 +2119,8 @@ sign_and_longness_words = ("short", "long", "signed", "unsigned")
base_type_start_words = \
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):
signed = 1
longness = 0
......@@ -2425,15 +2427,14 @@ def p_cdef_statement(s, ctx):
if ctx.visibility != 'extern':
error(pos, "C++ classes need to be declared extern")
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'):
error(pos, "C struct/union/enum definition not allowed here")
if ctx.overridable:
error(pos, "C struct/union/enum cannot be declared cpdef")
if s.systring == "enum":
return p_c_enum_definition(s, pos, ctx)
else:
return p_c_struct_or_union_definition(s, pos, ctx)
return p_struct_enum(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring == 'fused':
return p_fused_definition(s, pos, ctx)
else:
return p_c_func_or_var_declaration(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,
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):
pos = s.position()
visibility = prev_visibility
......@@ -2609,23 +2650,23 @@ def p_c_func_or_var_declaration(s, pos, ctx):
overridable = ctx.overridable)
return result
def p_typelist(s):
"""
parse a list of basic c types as part of a function call, like
cython.fused_type(int, long, double)
"""
types = []
pos = s.position()
while s.sy == 'IDENT':
types.append(p_c_base_type(s))
if s.sy != ',':
if s.sy != ')':
s.expect(',')
break
s.next()
return Nodes.FusedTypeNode(pos, types=types)
#def p_typelist(s):
# """
# parse a list of basic c types as part of a function call, like
# cython.fused_type(int, long, double)
# """
# types = []
# pos = s.position()
#
# while s.sy == 'IDENT':
# types.append(p_c_base_type(s))
# if s.sy != ',':
# if s.sy != ')':
# s.expect(',')
# break
# s.next()
#
# return Nodes.FusedTypeNode(pos, types=types)
def p_ctypedef_statement(s, ctx):
# s.sy == 'ctypedef'
......@@ -2638,30 +2679,10 @@ def p_ctypedef_statement(s, ctx):
ctx.api = 1
if s.sy == 'class':
return p_c_class_definition(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring in ('packed', 'struct', 'union', 'enum'):
if s.systring == 'enum':
return p_c_enum_definition(s, pos, ctx)
else:
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")
elif s.sy == 'IDENT' and s.systring in struct_enum_union:
return p_struct_enum(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring == 'fused':
return p_fused_definition(s, pos, ctx)
else:
base_type = p_c_base_type(s, nonempty = 1)
if base_type.name is None:
......
......@@ -2874,11 +2874,10 @@ def best_match(args, functions, pos=None, env=None):
if assignable:
if src_type == dst_type or dst_type.same_as(src_type):
pass # score 0
elif is_promotion(src_type, dst_type):
score[3] += 1
elif ((src_type.is_int and dst_type.is_int) or
(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:
score[1] += 1
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
from cython import fused_type
# This is all invalid
ctypedef foo(int) dtype1
ctypedef foo.bar(float) dtype2
ctypedef fused_type(foo) dtype3
dtype4 = cython.typedef(cython.fused_type(int, long, kw=None))
# ctypedef foo(int) dtype1
# ctypedef foo.bar(float) dtype2
# ctypedef fused_type(foo) dtype3
dtype4 = cython.fused_type(int, long, kw=None)
ctypedef public cython.fused_type(int, long) dtype7
ctypedef api cython.fused_type(int, long) dtype8
# ctypedef public cython.fused_type(int, long) dtype7
# ctypedef api cython.fused_type(int, long) dtype8
ctypedef cython.fused_type(short, short int, int) int_t
ctypedef cython.fused_type(int, long) int2_t
ctypedef cython.fused_type(int2_t, int) dtype9
int_t = cython.fused_type(short, short, int)
int2_t = cython.fused_type(int, long)
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):
print x, y
......@@ -29,21 +29,26 @@ func[float, int](x)
func[float, int](x, y, y)
func(x, y=y)
# This is all valid
ctypedef fused_type(int, long, float) dtype5
ctypedef cython.fused_type(int, long) dtype6
dtype5 = fused_type(int, long, float)
dtype6 = cython.fused_type(int, long)
func[float, int](x, y)
cdef fused fused1:
int
long long
ctypedef fused fused2:
int
long long
func(x, y)
_ERRORS = u"""
fused_types.pyx:7:13: Can only fuse types with cython.fused_type()
fused_types.pyx:8:17: Can only fuse types with cython.fused_type()
fused_types.pyx:9:20: 'foo' is not a type identifier
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:10:15: fused_type does not take keyword arguments
fused_types.pyx:15:38: Type specified multiple times
fused_types.pyx:17:33: 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: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)
......
......@@ -5,17 +5,28 @@ import math
ctypedef char *string_t
ctypedef cython.fused_type(int, long, float, string_t) fused_t
ctypedef cython.fused_type(int, long) other_t
ctypedef cython.fused_type(short int, int) base_t
ctypedef cython.fused_type(float complex, double complex,
int complex, long complex) complex_t
fused_t = cython.fused_type(int, long, float, string_t)
other_t = cython.fused_type(int, long)
base_t = cython.fused_type(short, int)
# 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 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,
double complex, int complex, long complex,
cython.p_p_int) composed_t
cdef fused composed_t:
char
int
float
string_t
cython.pp_int
float complex
double complex
int complex
long complex
cdef func(fused_t a, other_t b):
......
cimport cython
ctypedef cython.fused_type(int, float) unresolved_t
unresolved_t = cython.fused_type(int, float)
# mode: run
cimport cython
#from cython cimport p_double, p_int
from cython cimport integral
from cpython cimport Py_INCREF
from Cython import Shadow as pure_cython
ctypedef char * string_t
ctypedef cython.fused_type(float, double) floating
ctypedef cython.fused_type(int, long) integral
ctypedef cython.fused_type(int, long, float, double, string_t) fused_type1
ctypedef cython.fused_type(string_t) fused_type2
# floating = cython.fused_type(float, double) floating
# integral = cython.fused_type(int, long) integral
ctypedef cython.floating floating
fused_type1 = cython.fused_type(int, long, float, double, string_t)
fused_type2 = cython.fused_type(string_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 int *p_int
......
......@@ -30,10 +30,10 @@ cdef public class MyExt [ type MyExtType, object MyExtObject ]:
cdef unsigned char a
ctypedef char *string_t
ctypedef cython.fused_type(int, float) simple_t
ctypedef cython.fused_type(int, float, string_t) less_simple_t
ctypedef cython.fused_type(mystruct_t, myunion_t, MyExt) struct_t
ctypedef cython.fused_type(str, unicode, bytes) builtin_t
simple_t = cython.fused_type(int, float)
less_simple_t = cython.fused_type(int, float, string_t)
struct_t = cython.fused_type(mystruct_t, myunion_t, MyExt)
builtin_t = cython.fused_type(str, unicode, bytes)
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)
......@@ -43,7 +43,7 @@ cdef class TestFusedExtMethods(object):
cdef cython.floating 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)
......
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