Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Gwenaël Samain
cython
Commits
47ce63c9
Commit
47ce63c9
authored
Apr 27, 2011
by
Mark Florisson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support for fused types in cdef functions
parent
b386862c
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
616 additions
and
60 deletions
+616
-60
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+17
-4
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+48
-30
Cython/Compiler/Naming.py
Cython/Compiler/Naming.py
+1
-0
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+164
-4
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+51
-6
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+45
-7
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+132
-9
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+7
-0
Cython/Shadow.py
Cython/Shadow.py
+26
-0
tests/errors/fused_types.pyx
tests/errors/fused_types.pyx
+22
-0
tests/run/fused_types.pyx
tests/run/fused_types.pyx
+103
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
47ce63c9
...
@@ -2949,6 +2949,7 @@ class SimpleCallNode(CallNode):
...
@@ -2949,6 +2949,7 @@ class SimpleCallNode(CallNode):
else
:
else
:
for
arg
in
self
.
args
:
for
arg
in
self
.
args
:
arg
.
analyse_types
(
env
)
arg
.
analyse_types
(
env
)
if
self
.
self
and
func_type
.
args
:
if
self
.
self
and
func_type
.
args
:
# Coerce 'self' to the type expected by the method.
# Coerce 'self' to the type expected by the method.
self_arg
=
func_type
.
args
[
0
]
self_arg
=
func_type
.
args
[
0
]
...
@@ -2965,10 +2966,13 @@ class SimpleCallNode(CallNode):
...
@@ -2965,10 +2966,13 @@ class SimpleCallNode(CallNode):
def
function_type
(
self
):
def
function_type
(
self
):
# Return the type of the function being called, coercing a function
# Return the type of the function being called, coercing a function
# pointer to a function if necessary.
# pointer to a function if necessary. If the function has fused
# arguments, return the specific type.
func_type
=
self
.
function
.
type
func_type
=
self
.
function
.
type
if
func_type
.
is_ptr
:
if
func_type
.
is_ptr
:
func_type
=
func_type
.
base_type
func_type
=
func_type
.
base_type
return
func_type
return
func_type
def
is_simple
(
self
):
def
is_simple
(
self
):
...
@@ -2982,6 +2986,7 @@ class SimpleCallNode(CallNode):
...
@@ -2982,6 +2986,7 @@ class SimpleCallNode(CallNode):
if
self
.
function
.
type
is
error_type
:
if
self
.
function
.
type
is
error_type
:
self
.
type
=
error_type
self
.
type
=
error_type
return
return
if
self
.
function
.
type
.
is_cpp_class
:
if
self
.
function
.
type
.
is_cpp_class
:
overloaded_entry
=
self
.
function
.
type
.
scope
.
lookup
(
"operator()"
)
overloaded_entry
=
self
.
function
.
type
.
scope
.
lookup
(
"operator()"
)
if
overloaded_entry
is
None
:
if
overloaded_entry
is
None
:
...
@@ -2992,8 +2997,16 @@ class SimpleCallNode(CallNode):
...
@@ -2992,8 +2997,16 @@ class SimpleCallNode(CallNode):
overloaded_entry
=
self
.
function
.
entry
overloaded_entry
=
self
.
function
.
entry
else
:
else
:
overloaded_entry
=
None
overloaded_entry
=
None
if
overloaded_entry
:
if
overloaded_entry
:
entry
=
PyrexTypes
.
best_match
(
self
.
args
,
overloaded_entry
.
all_alternatives
(),
self
.
pos
)
if
overloaded_entry
.
fused_cfunction
:
specific_cdef_funcs
=
overloaded_entry
.
fused_cfunction
.
nodes
alternatives
=
[
n
.
entry
for
n
in
specific_cdef_funcs
]
else
:
alternatives
=
overloaded_entry
.
all_alternatives
()
entry
=
PyrexTypes
.
best_match
(
self
.
args
,
alternatives
,
self
.
pos
,
env
)
if
not
entry
:
if
not
entry
:
self
.
type
=
PyrexTypes
.
error_type
self
.
type
=
PyrexTypes
.
error_type
self
.
result_code
=
"<error>"
self
.
result_code
=
"<error>"
...
@@ -3130,8 +3143,8 @@ class SimpleCallNode(CallNode):
...
@@ -3130,8 +3143,8 @@ class SimpleCallNode(CallNode):
for
actual_arg
in
self
.
args
[
len
(
formal_args
):]:
for
actual_arg
in
self
.
args
[
len
(
formal_args
):]:
arg_list_code
.
append
(
actual_arg
.
result
())
arg_list_code
.
append
(
actual_arg
.
result
())
result
=
"%s(%s)"
%
(
self
.
function
.
result
(),
', '
.
join
(
arg_list_code
))
result
=
"%s(%s)"
%
(
self
.
function
.
result
(),
', '
.
join
(
arg_list_code
))
return
result
return
result
def
generate_result_code
(
self
,
code
):
def
generate_result_code
(
self
,
code
):
...
...
Cython/Compiler/ModuleNode.py
View file @
47ce63c9
...
@@ -156,13 +156,22 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -156,13 +156,22 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
f
.
close
()
f
.
close
()
def
generate_public_declaration
(
self
,
entry
,
h_code
,
i_code
):
def
generate_public_declaration
(
self
,
entry
,
h_code
,
i_code
):
if
entry
.
fused_cfunction
:
for
cfunction
in
entry
.
fused_cfunction
.
nodes
:
self
.
_generate_public_declaration
(
cfunction
.
entry
,
cfunction
.
entry
.
cname
,
h_code
,
i_code
)
else
:
self
.
_generate_public_declaration
(
entry
,
entry
.
cname
,
h_code
,
i_code
)
def
_generate_public_declaration
(
self
,
entry
,
cname
,
h_code
,
i_code
):
h_code
.
putln
(
"%s %s;"
%
(
h_code
.
putln
(
"%s %s;"
%
(
Naming
.
extern_c_macro
,
Naming
.
extern_c_macro
,
entry
.
type
.
declaration_code
(
entry
.
type
.
declaration_code
(
entry
.
cname
,
dll_linkage
=
"DL_IMPORT"
)))
cname
,
dll_linkage
=
"DL_IMPORT"
)))
if
i_code
:
if
i_code
:
i_code
.
putln
(
"cdef extern %s"
%
i_code
.
putln
(
"cdef extern %s"
%
entry
.
type
.
declaration_code
(
entry
.
cname
,
pyrex
=
1
))
entry
.
type
.
declaration_code
(
cname
,
pyrex
=
1
))
def
api_name
(
self
,
env
):
def
api_name
(
self
,
env
):
return
env
.
qualified_name
.
replace
(
"."
,
"__"
)
return
env
.
qualified_name
.
replace
(
"."
,
"__"
)
...
@@ -987,6 +996,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -987,6 +996,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def
generate_cfunction_predeclarations
(
self
,
env
,
code
,
definition
):
def
generate_cfunction_predeclarations
(
self
,
env
,
code
,
definition
):
for
entry
in
env
.
cfunc_entries
:
for
entry
in
env
.
cfunc_entries
:
if
entry
.
fused_cfunction
:
for
node
in
entry
.
fused_cfunction
.
nodes
:
self
.
_generate_cfunction_predeclaration
(
code
,
definition
,
node
.
entry
)
else
:
self
.
_generate_cfunction_predeclaration
(
code
,
definition
,
entry
)
def
_generate_cfunction_predeclaration
(
self
,
code
,
definition
,
entry
):
if
entry
.
inline_func_in_pxd
or
(
not
entry
.
in_cinclude
and
(
definition
if
entry
.
inline_func_in_pxd
or
(
not
entry
.
in_cinclude
and
(
definition
or
entry
.
defined_in_pxd
or
entry
.
visibility
==
'extern'
)):
or
entry
.
defined_in_pxd
or
entry
.
visibility
==
'extern'
)):
if
entry
.
visibility
==
'public'
:
if
entry
.
visibility
==
'public'
:
...
...
Cython/Compiler/Naming.py
View file @
47ce63c9
...
@@ -93,6 +93,7 @@ enc_scope_cname = pyrex_prefix + "enc_scope"
...
@@ -93,6 +93,7 @@ enc_scope_cname = pyrex_prefix + "enc_scope"
frame_cname
=
pyrex_prefix
+
"frame"
frame_cname
=
pyrex_prefix
+
"frame"
frame_code_cname
=
pyrex_prefix
+
"frame_code"
frame_code_cname
=
pyrex_prefix
+
"frame_code"
binding_cfunc
=
pyrex_prefix
+
"binding_PyCFunctionType"
binding_cfunc
=
pyrex_prefix
+
"binding_PyCFunctionType"
fused_func_prefix
=
pyrex_prefix
+
'fuse_'
genexpr_id_ref
=
'genexpr'
genexpr_id_ref
=
'genexpr'
...
...
Cython/Compiler/Nodes.py
View file @
47ce63c9
...
@@ -681,6 +681,7 @@ class CArgDeclNode(Node):
...
@@ -681,6 +681,7 @@ class CArgDeclNode(Node):
could_be_name
=
True
could_be_name
=
True
else
:
else
:
could_be_name
=
False
could_be_name
=
False
self
.
base_type
.
is_arg
=
True
base_type
=
self
.
base_type
.
analyse
(
env
,
could_be_name
=
could_be_name
)
base_type
=
self
.
base_type
.
analyse
(
env
,
could_be_name
=
could_be_name
)
if
hasattr
(
self
.
base_type
,
'arg_name'
)
and
self
.
base_type
.
arg_name
:
if
hasattr
(
self
.
base_type
,
'arg_name'
)
and
self
.
base_type
.
arg_name
:
self
.
declarator
.
name
=
self
.
base_type
.
arg_name
self
.
declarator
.
name
=
self
.
base_type
.
arg_name
...
@@ -777,9 +778,10 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
...
@@ -777,9 +778,10 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
if
scope
:
if
scope
:
if
scope
.
is_c_class_scope
:
if
scope
.
is_c_class_scope
:
scope
=
scope
.
global_scope
()
scope
=
scope
.
global_scope
()
entry
=
scope
.
lookup
(
self
.
name
)
if
entry
and
entry
.
is_type
:
type
=
scope
.
lookup_type
(
self
.
name
)
type
=
entry
.
type
if
type
is
not
None
:
pass
elif
could_be_name
:
elif
could_be_name
:
if
self
.
is_self_arg
and
env
.
is_c_class_scope
:
if
self
.
is_self_arg
and
env
.
is_c_class_scope
:
type
=
env
.
parent_type
type
=
env
.
parent_type
...
@@ -921,6 +923,26 @@ class CComplexBaseTypeNode(CBaseTypeNode):
...
@@ -921,6 +923,26 @@ class CComplexBaseTypeNode(CBaseTypeNode):
return
type
return
type
class
FusedTypeNode
(
CBaseTypeNode
):
"""
Represents a fused type in a ctypedef statement:
ctypedef cython.fused_type(int, long, long long) integral
types [CSimpleBaseTypeNode] is the list of types to be fused
"""
child_attrs
=
[]
def
analyse
(
self
,
env
):
self
.
types
=
[
type
.
analyse_as_type
(
env
)
for
type
in
self
.
types
]
if
len
(
self
.
types
)
==
1
:
return
self
.
types
[
0
]
return
PyrexTypes
.
FusedType
(
self
.
types
)
class
CVarDefNode
(
StatNode
):
class
CVarDefNode
(
StatNode
):
# C variable definition or forward/extern function declaration.
# C variable definition or forward/extern function declaration.
#
#
...
@@ -1162,15 +1184,29 @@ class CTypeDefNode(StatNode):
...
@@ -1162,15 +1184,29 @@ class CTypeDefNode(StatNode):
child_attrs
=
[
"base_type"
,
"declarator"
]
child_attrs
=
[
"base_type"
,
"declarator"
]
def
analyse_declarations
(
self
,
env
):
def
analyse_declarations
(
self
,
env
):
"""
If we are a fused type, do a normal type declaration, as we want
declared variables to have a FusedType type, not a CTypeDefType.
"""
base
=
self
.
base_type
.
analyse
(
env
)
base
=
self
.
base_type
.
analyse
(
env
)
name_declarator
,
type
=
self
.
declarator
.
analyse
(
base
,
env
)
name_declarator
,
type
=
self
.
declarator
.
analyse
(
base
,
env
)
name
=
name_declarator
.
name
name
=
name_declarator
.
name
cname
=
name_declarator
.
cname
cname
=
name_declarator
.
cname
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
self
.
in_pxd
and
not
env
.
in_cinclude
:
entry
.
defined_in_pxd
=
1
entry
.
defined_in_pxd
=
1
if
base
.
is_fused
:
# Omit the typedef declaration that self.declarator would produce
entry
.
in_cinclude
=
True
if
self
.
visibility
==
'public'
or
self
.
api
:
error
(
self
.
pos
,
"Fused types cannot be public or api"
)
base
.
name
=
name
def
analyse_expressions
(
self
,
env
):
def
analyse_expressions
(
self
,
env
):
pass
pass
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -1187,6 +1223,11 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1187,6 +1223,11 @@ class FuncDefNode(StatNode, BlockNode):
# needs_outer_scope boolean Whether or not this function requires outer scope
# needs_outer_scope boolean Whether or not this function requires outer scope
# directive_locals { string : NameNode } locals defined by cython.locals(...)
# directive_locals { string : NameNode } locals defined by cython.locals(...)
# has_fused_arguments boolean
# Whether this cdef function has fused parameters. This is needed
# by AnalyseDeclarationsTransform, so it can replace CFuncDefNodes
# with fused argument types with a FusedCFuncDefNode
py_func
=
None
py_func
=
None
assmt
=
None
assmt
=
None
needs_closure
=
False
needs_closure
=
False
...
@@ -1194,6 +1235,7 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1194,6 +1235,7 @@ class FuncDefNode(StatNode, BlockNode):
is_generator
=
False
is_generator
=
False
is_generator_body
=
False
is_generator_body
=
False
modifiers
=
[]
modifiers
=
[]
has_fused_arguments
=
False
def
analyse_default_values
(
self
,
env
):
def
analyse_default_values
(
self
,
env
):
genv
=
env
.
global_scope
()
genv
=
env
.
global_scope
()
...
@@ -1652,6 +1694,9 @@ class CFuncDefNode(FuncDefNode):
...
@@ -1652,6 +1694,9 @@ class CFuncDefNode(FuncDefNode):
# visibility 'private' or 'public' or 'extern'
# visibility 'private' or 'public' or 'extern'
# base_type CBaseTypeNode
# base_type CBaseTypeNode
# declarator CDeclaratorNode
# declarator CDeclaratorNode
# cfunc_declarator the CFuncDeclarator of this function
# (this is also available through declarator or a
# base thereof)
# body StatListNode
# body StatListNode
# api boolean
# api boolean
# decorators [DecoratorNode] list of decorators
# decorators [DecoratorNode] list of decorators
...
@@ -1667,6 +1712,7 @@ class CFuncDefNode(FuncDefNode):
...
@@ -1667,6 +1712,7 @@ class CFuncDefNode(FuncDefNode):
inline_in_pxd
=
False
inline_in_pxd
=
False
decorators
=
None
decorators
=
None
directive_locals
=
None
directive_locals
=
None
cname_postfix
=
None
def
unqualified_name
(
self
):
def
unqualified_name
(
self
):
return
self
.
entry
.
name
return
self
.
entry
.
name
...
@@ -1695,21 +1741,31 @@ class CFuncDefNode(FuncDefNode):
...
@@ -1695,21 +1741,31 @@ class CFuncDefNode(FuncDefNode):
declarator
=
self
.
declarator
declarator
=
self
.
declarator
while
not
hasattr
(
declarator
,
'args'
):
while
not
hasattr
(
declarator
,
'args'
):
declarator
=
declarator
.
base
declarator
=
declarator
.
base
self
.
cfunc_declarator
=
declarator
self
.
args
=
declarator
.
args
self
.
args
=
declarator
.
args
for
formal_arg
,
type_arg
in
zip
(
self
.
args
,
type
.
args
):
for
formal_arg
,
type_arg
in
zip
(
self
.
args
,
type
.
args
):
self
.
align_argument_type
(
env
,
type_arg
)
self
.
align_argument_type
(
env
,
type_arg
)
formal_arg
.
type
=
type_arg
.
type
formal_arg
.
type
=
type_arg
.
type
formal_arg
.
name
=
type_arg
.
name
formal_arg
.
name
=
type_arg
.
name
formal_arg
.
cname
=
type_arg
.
cname
formal_arg
.
cname
=
type_arg
.
cname
if
type_arg
.
type
.
is_fused
:
self
.
has_fused_arguments
=
True
if
type_arg
.
type
.
is_buffer
and
'inline'
in
self
.
modifiers
:
if
type_arg
.
type
.
is_buffer
and
'inline'
in
self
.
modifiers
:
warning
(
formal_arg
.
pos
,
"Buffer unpacking not optimized away."
,
1
)
warning
(
formal_arg
.
pos
,
"Buffer unpacking not optimized away."
,
1
)
name
=
name_declarator
.
name
name
=
name_declarator
.
name
cname
=
name_declarator
.
cname
cname
=
name_declarator
.
cname
self
.
entry
=
env
.
declare_cfunction
(
self
.
entry
=
env
.
declare_cfunction
(
name
,
type
,
self
.
pos
,
name
,
type
,
self
.
pos
,
cname
=
cname
,
visibility
=
self
.
visibility
,
cname
=
cname
,
visibility
=
self
.
visibility
,
defining
=
self
.
body
is
not
None
,
defining
=
self
.
body
is
not
None
,
api
=
self
.
api
,
modifiers
=
self
.
modifiers
)
api
=
self
.
api
,
modifiers
=
self
.
modifiers
)
self
.
entry
.
inline_func_in_pxd
=
self
.
inline_in_pxd
self
.
entry
.
inline_func_in_pxd
=
self
.
inline_in_pxd
self
.
return_type
=
type
.
return_type
self
.
return_type
=
type
.
return_type
if
self
.
return_type
.
is_array
and
visibility
!=
'extern'
:
if
self
.
return_type
.
is_array
and
visibility
!=
'extern'
:
...
@@ -1900,6 +1956,96 @@ class CFuncDefNode(FuncDefNode):
...
@@ -1900,6 +1956,96 @@ class CFuncDefNode(FuncDefNode):
code
.
putln
(
'}'
)
code
.
putln
(
'}'
)
class
FusedCFuncDefNode
(
StatListNode
):
"""
This node replaces a function with fused arguments. It deep-copies the
function for every permutation of fused types, and allocates a new local
scope for it. It keeps track of the original function in self.node, and
the entry of the original function in the symbol table is given the
'fused_cfunction' attribute which points back to us.
Then when a function lookup occurs (to e.g. call it), the call can be
dispatched to the right function.
node FuncDefNode the original function
nodes [FuncDefNode] list of copies of node with different specific types
"""
child_attrs
=
[
'nodes'
]
def
__init__
(
self
,
node
,
env
):
super
(
FusedCFuncDefNode
,
self
).
__init__
(
node
.
pos
)
self
.
nodes
=
self
.
stats
=
[]
self
.
node
=
node
self
.
copy_cdefs
(
node
.
type
.
get_fused_types
(),
env
)
# Perform some sanity checks. If anything fails, it's a bug
for
n
in
self
.
nodes
:
assert
not
n
.
type
.
is_fused
assert
not
n
.
local_scope
.
return_type
.
is_fused
if
node
.
return_type
.
is_fused
:
assert
not
n
.
return_type
.
is_fused
assert
node
.
type
.
is_fused
node
.
entry
.
fused_cfunction
=
self
def
copy_cdefs
(
self
,
fused_types
,
env
):
"""
Gives a list of fused types and the parent environment, make copies
of the original cdef function.
"""
permutations
=
self
.
get_all_specific_permutations
(
fused_types
)
for
cname
,
fused_to_specific
in
permutations
:
copied_node
=
copy
.
deepcopy
(
self
.
node
)
# Make the types in our CFuncType specific
newtype
=
copied_node
.
type
.
specialize
(
fused_to_specific
)
copied_node
.
type
=
newtype
copied_node
.
entry
.
type
=
newtype
copied_node
.
return_type
=
newtype
.
return_type
copied_node
.
create_local_scope
(
env
)
copied_node
.
local_scope
.
fused_to_specific
=
fused_to_specific
# This is copied from the original function, set it to false to
# stop recursivon
copied_node
.
has_fused_arguments
=
False
self
.
nodes
.
append
(
copied_node
)
# Make the argument types in the CFuncDeclarator specific
for
arg
in
copied_node
.
cfunc_declarator
.
args
:
arg
.
type
=
arg
.
type
.
specialize
(
fused_to_specific
)
cname
=
'%s%s%s'
%
(
Naming
.
fused_func_prefix
,
cname
,
self
.
node
.
entry
.
func_cname
)
copied_node
.
entry
.
func_cname
=
copied_node
.
entry
.
cname
=
cname
def
get_all_specific_permutations
(
self
,
fused_types
):
"""
Permute all the types. For every specific instance of a fused type, we
want all other specific instances of all other fused types.
It returns an iterable of two-tuples of the cname that should prefix
the cname of the function, and a dict mapping any fused types to their
respective specific types.
"""
fused_type
=
fused_types
[
0
]
for
specific_type
in
fused_type
.
types
:
cname
=
str
(
specific_type
)
result_fused_to_specific
=
{
fused_type
:
specific_type
}
if
len
(
fused_types
)
>
1
:
it
=
self
.
get_all_specific_permutations
(
fused_types
[
1
:])
for
next_cname
,
fused_to_specific
in
it
:
d
=
dict
(
fused_to_specific
,
**
result_fused_to_specific
)
yield
'%s_%s'
%
(
cname
,
next_cname
),
d
else
:
yield
cname
,
result_fused_to_specific
class
PyArgDeclNode
(
Node
):
class
PyArgDeclNode
(
Node
):
# Argument which must be a Python object (used
# Argument which must be a Python object (used
# for * and ** arguments).
# for * and ** arguments).
...
@@ -3653,6 +3799,20 @@ class SingleAssignmentNode(AssignmentNode):
...
@@ -3653,6 +3799,20 @@ class SingleAssignmentNode(AssignmentNode):
if
len
(
args
)
>
2
or
kwds
is
not
None
:
if
len
(
args
)
>
2
or
kwds
is
not
None
:
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(...))
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"
)
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
47ce63c9
...
@@ -610,8 +610,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
...
@@ -610,8 +610,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
'operator.comma'
:
ExprNodes
.
c_binop_constructor
(
','
),
'operator.comma'
:
ExprNodes
.
c_binop_constructor
(
','
),
}
}
special_methods
=
cython
.
set
([
'declare'
,
'union'
,
'struct'
,
'typedef'
,
'sizeof'
,
special_methods
=
cython
.
set
([
'declare'
,
'union'
,
'struct'
,
'typedef'
,
'cast'
,
'pointer'
,
'compiled'
,
'NULL'
])
'sizeof'
,
'cast'
,
'pointer'
,
'compiled'
,
'NULL'
,
'fused_type'
])
special_methods
.
update
(
unop_method_nodes
.
keys
())
special_methods
.
update
(
unop_method_nodes
.
keys
())
def
__init__
(
self
,
context
,
compilation_directive_defaults
):
def
__init__
(
self
,
context
,
compilation_directive_defaults
):
...
@@ -896,6 +897,36 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
...
@@ -896,6 +897,36 @@ 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
WithTransform
(
CythonTransform
,
SkipDeclarations
):
class
WithTransform
(
CythonTransform
,
SkipDeclarations
):
# EXCINFO is manually set to a variable that contains
# EXCINFO is manually set to a variable that contains
...
@@ -1115,6 +1146,14 @@ if VALUE is not None:
...
@@ -1115,6 +1146,14 @@ if VALUE is not None:
return
node
return
node
def
visit_FuncDefNode
(
self
,
node
):
def
visit_FuncDefNode
(
self
,
node
):
"""
Analyse a function and its body, as that hasn't happend yet. Also
analyse the directive_locals set by @cython.locals(). Then, if we are
a function with fused arguments, replace the function (after it has
declared itself in the symbol table!) with a FusedCFuncDefNode, and
analyse its children (which are in turn normal functions). If we're a
normal function, just analyse the body of the function.
"""
self
.
seen_vars_stack
.
append
(
cython
.
set
())
self
.
seen_vars_stack
.
append
(
cython
.
set
())
lenv
=
node
.
local_scope
lenv
=
node
.
local_scope
node
.
body
.
analyse_control_flow
(
lenv
)
# this will be totally refactored
node
.
body
.
analyse_control_flow
(
lenv
)
# this will be totally refactored
...
@@ -1126,10 +1165,16 @@ if VALUE is not None:
...
@@ -1126,10 +1165,16 @@ if VALUE is not None:
lenv
.
declare_var
(
var
,
type
,
type_node
.
pos
)
lenv
.
declare_var
(
var
,
type
,
type_node
.
pos
)
else
:
else
:
error
(
type_node
.
pos
,
"Not a type"
)
error
(
type_node
.
pos
,
"Not a type"
)
if
node
.
has_fused_arguments
:
node
=
Nodes
.
FusedCFuncDefNode
(
node
,
self
.
env_stack
[
-
1
])
self
.
visitchildren
(
node
)
else
:
node
.
body
.
analyse_declarations
(
lenv
)
node
.
body
.
analyse_declarations
(
lenv
)
self
.
env_stack
.
append
(
lenv
)
self
.
env_stack
.
append
(
lenv
)
self
.
visitchildren
(
node
)
self
.
visitchildren
(
node
)
self
.
env_stack
.
pop
()
self
.
env_stack
.
pop
()
self
.
seen_vars_stack
.
pop
()
self
.
seen_vars_stack
.
pop
()
return
node
return
node
...
...
Cython/Compiler/Parsing.py
View file @
47ce63c9
...
@@ -2572,6 +2572,24 @@ def p_c_func_or_var_declaration(s, pos, ctx):
...
@@ -2572,6 +2572,24 @@ def p_c_func_or_var_declaration(s, pos, ctx):
overridable
=
ctx
.
overridable
)
overridable
=
ctx
.
overridable
)
return
result
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_ctypedef_statement
(
s
,
ctx
):
def
p_ctypedef_statement
(
s
,
ctx
):
# s.sy == 'ctypedef'
# s.sy == 'ctypedef'
pos
=
s
.
position
()
pos
=
s
.
position
()
...
@@ -2588,10 +2606,30 @@ def p_ctypedef_statement(s, ctx):
...
@@ -2588,10 +2606,30 @@ def p_ctypedef_statement(s, ctx):
return
p_c_enum_definition
(
s
,
pos
,
ctx
)
return
p_c_enum_definition
(
s
,
pos
,
ctx
)
else
:
else
:
return
p_c_struct_or_union_definition
(
s
,
pos
,
ctx
)
return
p_c_struct_or_union_definition
(
s
,
pos
,
ctx
)
elif
looking_at_expr
(
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
:
s
.
error
(
"Syntax error in ctypedef statement"
)
s
.
error
(
"Syntax error in ctypedef statement"
)
declarator
=
p_c_declarator
(
s
,
ctx
,
is_type
=
1
,
nonempty
=
1
)
declarator
=
p_c_declarator
(
s
,
ctx
,
is_type
=
1
,
nonempty
=
1
)
s
.
expect_newline
(
"Syntax error in ctypedef statement"
)
s
.
expect_newline
(
"Syntax error in ctypedef statement"
)
return
Nodes
.
CTypeDefNode
(
return
Nodes
.
CTypeDefNode
(
...
...
Cython/Compiler/PyrexTypes.py
View file @
47ce63c9
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
# Pyrex - Types
# Pyrex - Types
#
#
import
cython
from
Code
import
UtilityCode
from
Code
import
UtilityCode
import
StringEncoding
import
StringEncoding
import
Naming
import
Naming
...
@@ -12,6 +14,9 @@ class BaseType(object):
...
@@ -12,6 +14,9 @@ class BaseType(object):
#
#
# Base class for all Pyrex types including pseudo-types.
# Base class for all Pyrex types including pseudo-types.
# List of attribute names of any subtypes
subtypes
=
[]
def
can_coerce_to_pyobject
(
self
,
env
):
def
can_coerce_to_pyobject
(
self
,
env
):
return
False
return
False
...
@@ -27,6 +32,42 @@ class BaseType(object):
...
@@ -27,6 +32,42 @@ class BaseType(object):
else
:
else
:
return
base_code
return
base_code
def
__deepcopy__
(
self
,
memo
):
"""
Types never need to be copied, if we do copy, Unfortunate Things
Will Happen!
"""
return
self
def
get_fused_types
(
self
,
result
=
None
,
seen
=
None
):
if
self
.
subtypes
:
def
add_fused_types
(
types
):
for
type
in
types
or
():
if
type
not
in
seen
:
seen
.
add
(
type
)
result
.
append
(
type
)
if
result
is
None
:
result
=
[]
seen
=
cython
.
set
()
for
attr
in
self
.
subtypes
:
list_or_subtype
=
getattr
(
self
,
attr
)
if
isinstance
(
list_or_subtype
,
BaseType
):
list_or_subtype
.
get_fused_types
(
result
,
seen
)
else
:
for
subtype
in
list_or_subtype
:
subtype
.
get_fused_types
(
result
,
seen
)
return
result
return
None
is_fused
=
property
(
get_fused_types
,
doc
=
"Whether this type or any of its "
"subtypes is a fused type"
)
class
PyrexType
(
BaseType
):
class
PyrexType
(
BaseType
):
#
#
# Base class for all Pyrex types.
# Base class for all Pyrex types.
...
@@ -196,6 +237,7 @@ class CTypedefType(BaseType):
...
@@ -196,6 +237,7 @@ class CTypedefType(BaseType):
to_py_utility_code
=
None
to_py_utility_code
=
None
from_py_utility_code
=
None
from_py_utility_code
=
None
subtypes
=
[
'typedef_base_type'
]
def
__init__
(
self
,
name
,
base_type
,
cname
,
is_external
=
0
):
def
__init__
(
self
,
name
,
base_type
,
cname
,
is_external
=
0
):
assert
not
base_type
.
is_complex
assert
not
base_type
.
is_complex
...
@@ -314,6 +356,9 @@ class BufferType(BaseType):
...
@@ -314,6 +356,9 @@ class BufferType(BaseType):
is_buffer
=
1
is_buffer
=
1
writable
=
True
writable
=
True
subtypes
=
[
'dtype'
]
def
__init__
(
self
,
base
,
dtype
,
ndim
,
mode
,
negative_indices
,
cast
):
def
__init__
(
self
,
base
,
dtype
,
ndim
,
mode
,
negative_indices
,
cast
):
self
.
base
=
base
self
.
base
=
base
self
.
dtype
=
dtype
self
.
dtype
=
dtype
...
@@ -618,6 +663,45 @@ class CType(PyrexType):
...
@@ -618,6 +663,45 @@ class CType(PyrexType):
return
0
return
0
class
FusedType
(
CType
):
"""
Represents a Fused Type. All it needs to do is keep track of the types
it aggregates, as it will be replaced with its specific version wherever
needed.
See http://wiki.cython.org/enhancements/fusedtypes
types [CSimpleBaseTypeNode] is the list of types to be fused
name str the name of the ctypedef
"""
is_fused
=
1
def
__init__
(
self
,
types
):
self
.
types
=
types
def
declaration_code
(
self
,
entity_code
,
for_display
=
0
,
dll_linkage
=
None
,
pyrex
=
0
):
if
pyrex
or
for_display
:
return
self
.
name
raise
Exception
(
"This may never happen, please report a bug"
)
def
__repr__
(
self
):
return
'FusedType(name=%r)'
%
self
.
name
def
specialize
(
self
,
values
):
return
values
[
self
]
def
get_fused_types
(
self
,
result
=
None
,
seen
=
None
):
if
result
is
None
:
return
[
self
]
if
self
not
in
seen
:
result
.
append
(
self
)
seen
.
add
(
self
)
class
CVoidType
(
CType
):
class
CVoidType
(
CType
):
#
#
# C "void" type
# C "void" type
...
@@ -1532,6 +1616,8 @@ class CArrayType(CType):
...
@@ -1532,6 +1616,8 @@ class CArrayType(CType):
is_array
=
1
is_array
=
1
subtypes
=
[
'base_type'
]
def
__init__
(
self
,
base_type
,
size
):
def
__init__
(
self
,
base_type
,
size
):
self
.
base_type
=
base_type
self
.
base_type
=
base_type
self
.
size
=
size
self
.
size
=
size
...
@@ -1578,6 +1664,8 @@ class CPtrType(CType):
...
@@ -1578,6 +1664,8 @@ class CPtrType(CType):
is_ptr
=
1
is_ptr
=
1
default_value
=
"0"
default_value
=
"0"
subtypes
=
[
'base_type'
]
def
__init__
(
self
,
base_type
):
def
__init__
(
self
,
base_type
):
self
.
base_type
=
base_type
self
.
base_type
=
base_type
...
@@ -1676,6 +1764,8 @@ class CFuncType(CType):
...
@@ -1676,6 +1764,8 @@ class CFuncType(CType):
is_cfunction
=
1
is_cfunction
=
1
original_sig
=
None
original_sig
=
None
subtypes
=
[
'return_type'
,
'args'
]
def
__init__
(
self
,
return_type
,
args
,
has_varargs
=
0
,
def
__init__
(
self
,
return_type
,
args
,
has_varargs
=
0
,
exception_value
=
None
,
exception_check
=
0
,
calling_convention
=
""
,
exception_value
=
None
,
exception_check
=
0
,
calling_convention
=
""
,
nogil
=
0
,
with_gil
=
0
,
is_overridable
=
0
,
optional_arg_count
=
0
,
nogil
=
0
,
with_gil
=
0
,
is_overridable
=
0
,
optional_arg_count
=
0
,
...
@@ -1915,7 +2005,7 @@ class CFuncType(CType):
...
@@ -1915,7 +2005,7 @@ class CFuncType(CType):
return
self
.
op_arg_struct
.
base_type
.
scope
.
lookup
(
arg_name
).
cname
return
self
.
op_arg_struct
.
base_type
.
scope
.
lookup
(
arg_name
).
cname
class
CFuncTypeArg
(
object
):
class
CFuncTypeArg
(
BaseType
):
# name string
# name string
# cname string
# cname string
# type PyrexType
# type PyrexType
...
@@ -1926,6 +2016,8 @@ class CFuncTypeArg(object):
...
@@ -1926,6 +2016,8 @@ class CFuncTypeArg(object):
or_none
=
False
or_none
=
False
accept_none
=
True
accept_none
=
True
subtypes
=
[
'type'
]
def
__init__
(
self
,
name
,
type
,
pos
,
cname
=
None
):
def
__init__
(
self
,
name
,
type
,
pos
,
cname
=
None
):
self
.
name
=
name
self
.
name
=
name
if
cname
is
not
None
:
if
cname
is
not
None
:
...
@@ -2478,7 +2570,7 @@ def is_promotion(src_type, dst_type):
...
@@ -2478,7 +2570,7 @@ def is_promotion(src_type, dst_type):
return
src_type
.
is_float
and
src_type
.
rank
<=
dst_type
.
rank
return
src_type
.
is_float
and
src_type
.
rank
<=
dst_type
.
rank
return
False
return
False
def
best_match
(
args
,
functions
,
pos
=
None
):
def
best_match
(
args
,
functions
,
pos
=
None
,
env
=
None
):
"""
"""
Given a list args of arguments and a list of functions, choose one
Given a list args of arguments and a list of functions, choose one
to call which seems to be the "best" fit for this list of arguments.
to call which seems to be the "best" fit for this list of arguments.
...
@@ -2546,12 +2638,33 @@ def best_match(args, functions, pos=None):
...
@@ -2546,12 +2638,33 @@ def best_match(args, functions, pos=None):
possibilities
=
[]
possibilities
=
[]
bad_types
=
[]
bad_types
=
[]
needed_coercions
=
{}
for
func
,
func_type
in
candidates
:
for
func
,
func_type
in
candidates
:
score
=
[
0
,
0
,
0
]
score
=
[
0
,
0
,
0
]
for
i
in
range
(
min
(
len
(
args
),
len
(
func_type
.
args
))):
for
i
in
range
(
min
(
len
(
args
),
len
(
func_type
.
args
))):
src_type
=
args
[
i
].
type
src_type
=
args
[
i
].
type
dst_type
=
func_type
.
args
[
i
].
type
dst_type
=
func_type
.
args
[
i
].
type
if
dst_type
.
assignable_from
(
src_type
):
assignable
=
dst_type
.
assignable_from
(
src_type
)
# Now take care of normal string literals. So when you call a cdef
# function that takes a char *, the coercion will mean that the
# type will simply become bytes. We need to do this coercion
# manually for overloaded and fused functions
if
not
assignable
and
src_type
.
is_pyobject
:
if
(
src_type
.
is_builtin_type
and
src_type
.
name
==
'str'
and
dst_type
.
resolve
()
is
c_char_ptr_type
):
c_src_type
=
c_char_ptr_type
else
:
c_src_type
=
src_type
.
default_coerced_ctype
()
if
c_src_type
:
assignable
=
dst_type
.
assignable_from
(
c_src_type
)
if
assignable
:
src_type
=
c_src_type
needed_coercions
[
func
]
=
i
,
dst_type
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
):
elif
is_promotion
(
src_type
,
dst_type
):
...
@@ -2567,18 +2680,28 @@ def best_match(args, functions, pos=None):
...
@@ -2567,18 +2680,28 @@ def best_match(args, functions, pos=None):
break
break
else
:
else
:
possibilities
.
append
((
score
,
func
))
# so we can sort it
possibilities
.
append
((
score
,
func
))
# so we can sort it
if
possibilities
:
if
possibilities
:
possibilities
.
sort
()
possibilities
.
sort
()
if
len
(
possibilities
)
>
1
and
possibilities
[
0
][
0
]
==
possibilities
[
1
][
0
]:
if
len
(
possibilities
)
>
1
and
possibilities
[
0
][
0
]
==
possibilities
[
1
][
0
]:
if
pos
is
not
None
:
if
pos
is
not
None
:
error
(
pos
,
"ambiguous overloaded method"
)
error
(
pos
,
"ambiguous overloaded method"
)
return
None
return
None
return
possibilities
[
0
][
1
]
function
=
possibilities
[
0
][
1
]
if
function
in
needed_coercions
and
env
:
arg_i
,
coerce_to_type
=
needed_coercions
[
function
]
args
[
arg_i
]
=
args
[
arg_i
].
coerce_to
(
coerce_to_type
,
env
)
return
function
if
pos
is
not
None
:
if
pos
is
not
None
:
if
len
(
bad_types
)
==
1
:
if
len
(
bad_types
)
==
1
:
error
(
pos
,
bad_types
[
0
][
1
])
error
(
pos
,
bad_types
[
0
][
1
])
else
:
else
:
error
(
pos
,
"no suitable method found"
)
error
(
pos
,
"no suitable method found"
)
return
None
return
None
def
widest_numeric_type
(
type1
,
type2
):
def
widest_numeric_type
(
type1
,
type2
):
...
...
Cython/Compiler/Symtab.py
View file @
47ce63c9
...
@@ -176,6 +176,7 @@ class Entry(object):
...
@@ -176,6 +176,7 @@ class Entry(object):
buffer_aux = None
buffer_aux = None
prev_entry = None
prev_entry = None
might_overflow = 0
might_overflow = 0
fused_cfunction = None
def __init__(self, name, cname, type, pos = None, init = None):
def __init__(self, name, cname, type, pos = None, init = None):
self.name = name
self.name = name
...
@@ -241,6 +242,7 @@ class Scope(object):
...
@@ -241,6 +242,7 @@ class Scope(object):
scope_prefix = ""
scope_prefix = ""
in_cinclude = 0
in_cinclude = 0
nogil = 0
nogil = 0
fused_to_specific = None
def __init__(self, name, outer_scope, parent_scope):
def __init__(self, name, outer_scope, parent_scope):
# The outer_scope is the next scope in the lookup chain.
# The outer_scope is the next scope in the lookup chain.
...
@@ -279,6 +281,9 @@ class Scope(object):
...
@@ -279,6 +281,9 @@ class Scope(object):
self.return_type = None
self.return_type = None
self.id_counters = {}
self.id_counters = {}
def __deepcopy__(self, memo):
return self
def start_branching(self, pos):
def start_branching(self, pos):
self.control_flow = self.control_flow.start_branch(pos)
self.control_flow = self.control_flow.start_branch(pos)
...
@@ -677,6 +682,8 @@ class Scope(object):
...
@@ -677,6 +682,8 @@ class Scope(object):
def lookup_type(self, name):
def lookup_type(self, name):
entry = self.lookup(name)
entry = self.lookup(name)
if entry and entry.is_type:
if entry and entry.is_type:
if entry.type.is_fused and self.fused_to_specific:
return entry.type.specialize(self.fused_to_specific)
return entry.type
return entry.type
def lookup_operator(self, operator, operands):
def lookup_operator(self, operator, operands):
...
...
Cython/Shadow.py
View file @
47ce63c9
...
@@ -225,6 +225,30 @@ class typedef(CythonType):
...
@@ -225,6 +225,30 @@ class typedef(CythonType):
value
=
cast
(
self
.
_basetype
,
*
arg
)
value
=
cast
(
self
.
_basetype
,
*
arg
)
return
value
return
value
class
_FusedType
(
CythonType
):
def
__call__
(
self
,
type
,
value
):
return
value
def
fused_type
(
*
args
):
if
not
args
:
raise
TypeError
(
"Expected at least one type as argument"
)
rank
=
-
1
for
type
in
args
:
if
type
not
in
(
py_int
,
py_long
,
py_float
,
py_complex
):
break
if
type_ordering
.
index
(
type
)
>
rank
:
result_type
=
type
else
:
return
result_type
# Not a simple numeric type, return a fused type instance. The result
# isn't really meant to be used, as we can't keep track of the context in
# pure-mode. Casting won't do anything in this case.
return
_FusedType
()
py_int
=
int
py_int
=
int
...
@@ -277,3 +301,5 @@ for t in int_types + float_types + complex_types + other_types:
...
@@ -277,3 +301,5 @@ for t in int_types + float_types + complex_types + other_types:
void
=
typedef
(
None
)
void
=
typedef
(
None
)
NULL
=
p_void
(
0
)
NULL
=
p_void
(
0
)
type_ordering
=
[
py_int
,
py_long
,
py_float
,
py_complex
]
\ No newline at end of file
tests/errors/fused_types.pyx
0 → 100644
View file @
47ce63c9
# mode: error
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
))
# This is all valid
ctypedef
fused_type
(
int
,
long
,
float
)
dtype5
ctypedef
cython
.
fused_type
(
int
,
long
)
dtype6
_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
"""
tests/run/fused_types.pyx
0 → 100644
View file @
47ce63c9
# mode: run
cimport
cython
from
cpython
cimport
Py_INCREF
from
Cython
import
Shadow
as
pure_cython
ctypedef
char
*
string_t
ctypedef
cython
.
fused_type
(
int
,
long
,
float
,
double
,
string_t
)
fused_type1
ctypedef
cython
.
fused_type
(
string_t
)
fused_type2
def
test_pure
():
"""
>>> test_pure()
(10+0j)
"""
mytype
=
pure_cython
.
typedef
(
pure_cython
.
fused_type
(
int
,
long
,
complex
))
print
mytype
(
10
)
cdef
cdef
_func_with_fused_args
(
fused_type1
x
,
fused_type1
y
,
fused_type2
z
):
print
x
,
y
,
z
return
x
+
y
def
test_cdef_func_with_fused_args
():
"""
>>> test_cdef_func_with_fused_args()
spam ham eggs
spamham
10 20 butter
30
4.2 8.6 bunny
12.8
"""
print
cdef
_func_with_fused_args
(
'spam'
,
'ham'
,
'eggs'
)
print
cdef
_func_with_fused_args
(
10
,
20
,
'butter'
)
print
cdef
_func_with_fused_args
(
4.2
,
8.6
,
'bunny'
)
cdef
fused_type1
fused_with_pointer
(
fused_type1
*
array
):
for
i
in
range
(
5
):
print
array
[
i
]
obj
=
array
[
0
]
+
array
[
1
]
+
array
[
2
]
+
array
[
3
]
+
array
[
4
]
# if cython.typeof(fused_type1) is string_t:
Py_INCREF
(
obj
)
return
obj
def
test_fused_with_pointer
():
"""
>>> test_fused_with_pointer()
0
1
2
3
4
10
<BLANKLINE>
0
1
2
3
4
10
<BLANKLINE>
0.0
1.0
2.0
3.0
4.0
10.0
<BLANKLINE>
humpty
dumpty
fall
splatch
breakfast
humptydumptyfallsplatchbreakfast
"""
cdef
int
int_array
[
5
]
cdef
long
long_array
[
5
]
cdef
float
float_array
[
5
]
cdef
string_t
string_array
[
5
]
cdef
char
*
s1
=
"humpty"
,
*
s2
=
"dumpty"
,
*
s3
=
"fall"
,
*
s4
=
"splatch"
,
*
s5
=
"breakfast"
strings
=
[
"humpty"
,
"dumpty"
,
"fall"
,
"splatch"
,
"breakfast"
]
for
i
in
range
(
5
):
int_array
[
i
]
=
i
long_array
[
i
]
=
i
float_array
[
i
]
=
i
s
=
strings
[
i
]
string_array
[
i
]
=
s
print
fused_with_pointer
(
int_array
)
print
print
fused_with_pointer
(
long_array
)
print
print
fused_with_pointer
(
float_array
)
print
print
fused_with_pointer
(
string_array
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment