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
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
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
Expand all
Hide 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):
else
:
for
arg
in
self
.
args
:
arg
.
analyse_types
(
env
)
if
self
.
self
and
func_type
.
args
:
# Coerce 'self' to the type expected by the method.
self_arg
=
func_type
.
args
[
0
]
...
...
@@ -2965,10 +2966,13 @@ class SimpleCallNode(CallNode):
def
function_type
(
self
):
# 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
if
func_type
.
is_ptr
:
func_type
=
func_type
.
base_type
return
func_type
def
is_simple
(
self
):
...
...
@@ -2982,6 +2986,7 @@ class SimpleCallNode(CallNode):
if
self
.
function
.
type
is
error_type
:
self
.
type
=
error_type
return
if
self
.
function
.
type
.
is_cpp_class
:
overloaded_entry
=
self
.
function
.
type
.
scope
.
lookup
(
"operator()"
)
if
overloaded_entry
is
None
:
...
...
@@ -2992,8 +2997,16 @@ class SimpleCallNode(CallNode):
overloaded_entry
=
self
.
function
.
entry
else
:
overloaded_entry
=
None
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
:
self
.
type
=
PyrexTypes
.
error_type
self
.
result_code
=
"<error>"
...
...
@@ -3130,8 +3143,8 @@ class SimpleCallNode(CallNode):
for
actual_arg
in
self
.
args
[
len
(
formal_args
):]:
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
def
generate_result_code
(
self
,
code
):
...
...
Cython/Compiler/ModuleNode.py
View file @
47ce63c9
...
...
@@ -156,13 +156,22 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
f
.
close
()
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;"
%
(
Naming
.
extern_c_macro
,
entry
.
type
.
declaration_code
(
entry
.
cname
,
dll_linkage
=
"DL_IMPORT"
)))
cname
,
dll_linkage
=
"DL_IMPORT"
)))
if
i_code
:
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
):
return
env
.
qualified_name
.
replace
(
"."
,
"__"
)
...
...
@@ -987,34 +996,43 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def
generate_cfunction_predeclarations
(
self
,
env
,
code
,
definition
):
for
entry
in
env
.
cfunc_entries
:
if
entry
.
inline_func_in_pxd
or
(
not
entry
.
in_cinclude
and
(
definition
or
entry
.
defined_in_pxd
or
entry
.
visibility
==
'extern'
)):
if
entry
.
visibility
==
'public'
:
storage_class
=
"%s "
%
Naming
.
extern_c_macro
dll_linkage
=
"DL_EXPORT"
elif
entry
.
visibility
==
'extern'
:
storage_class
=
"%s "
%
Naming
.
extern_c_macro
dll_linkage
=
"DL_IMPORT"
elif
entry
.
visibility
==
'private'
:
storage_class
=
"static "
dll_linkage
=
None
else
:
storage_class
=
"static "
dll_linkage
=
None
type
=
entry
.
type
if
not
definition
and
entry
.
defined_in_pxd
:
type
=
CPtrType
(
type
)
header
=
type
.
declaration_code
(
entry
.
cname
,
dll_linkage
=
dll_linkage
)
if
entry
.
func_modifiers
:
modifiers
=
"%s "
%
' '
.
join
(
entry
.
func_modifiers
).
upper
()
else
:
modifiers
=
''
code
.
putln
(
"%s%s%s; /*proto*/"
%
(
storage_class
,
modifiers
,
header
))
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
or
entry
.
defined_in_pxd
or
entry
.
visibility
==
'extern'
)):
if
entry
.
visibility
==
'public'
:
storage_class
=
"%s "
%
Naming
.
extern_c_macro
dll_linkage
=
"DL_EXPORT"
elif
entry
.
visibility
==
'extern'
:
storage_class
=
"%s "
%
Naming
.
extern_c_macro
dll_linkage
=
"DL_IMPORT"
elif
entry
.
visibility
==
'private'
:
storage_class
=
"static "
dll_linkage
=
None
else
:
storage_class
=
"static "
dll_linkage
=
None
type
=
entry
.
type
if
not
definition
and
entry
.
defined_in_pxd
:
type
=
CPtrType
(
type
)
header
=
type
.
declaration_code
(
entry
.
cname
,
dll_linkage
=
dll_linkage
)
if
entry
.
func_modifiers
:
modifiers
=
"%s "
%
' '
.
join
(
entry
.
func_modifiers
).
upper
()
else
:
modifiers
=
''
code
.
putln
(
"%s%s%s; /*proto*/"
%
(
storage_class
,
modifiers
,
header
))
def
generate_typeobj_definitions
(
self
,
env
,
code
):
full_module_name
=
env
.
qualified_name
...
...
Cython/Compiler/Naming.py
View file @
47ce63c9
...
...
@@ -93,6 +93,7 @@ enc_scope_cname = pyrex_prefix + "enc_scope"
frame_cname
=
pyrex_prefix
+
"frame"
frame_code_cname
=
pyrex_prefix
+
"frame_code"
binding_cfunc
=
pyrex_prefix
+
"binding_PyCFunctionType"
fused_func_prefix
=
pyrex_prefix
+
'fuse_'
genexpr_id_ref
=
'genexpr'
...
...
Cython/Compiler/Nodes.py
View file @
47ce63c9
This diff is collapsed.
Click to expand it.
Cython/Compiler/ParseTreeTransforms.py
View file @
47ce63c9
...
...
@@ -610,8 +610,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
'operator.comma'
:
ExprNodes
.
c_binop_constructor
(
','
),
}
special_methods
=
cython
.
set
([
'declare'
,
'union'
,
'struct'
,
'typedef'
,
'sizeof'
,
'cast'
,
'pointer'
,
'compiled'
,
'NULL'
])
special_methods
=
cython
.
set
([
'declare'
,
'union'
,
'struct'
,
'typedef'
,
'sizeof'
,
'cast'
,
'pointer'
,
'compiled'
,
'NULL'
,
'fused_type'
])
special_methods
.
update
(
unop_method_nodes
.
keys
())
def
__init__
(
self
,
context
,
compilation_directive_defaults
):
...
...
@@ -896,6 +897,36 @@ 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
WithTransform
(
CythonTransform
,
SkipDeclarations
):
# EXCINFO is manually set to a variable that contains
...
...
@@ -1115,6 +1146,14 @@ if VALUE is not None:
return
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
())
lenv
=
node
.
local_scope
node
.
body
.
analyse_control_flow
(
lenv
)
# this will be totally refactored
...
...
@@ -1126,10 +1165,16 @@ if VALUE is not None:
lenv
.
declare_var
(
var
,
type
,
type_node
.
pos
)
else
:
error
(
type_node
.
pos
,
"Not a type"
)
node
.
body
.
analyse_declarations
(
lenv
)
self
.
env_stack
.
append
(
lenv
)
self
.
visitchildren
(
node
)
self
.
env_stack
.
pop
()
if
node
.
has_fused_arguments
:
node
=
Nodes
.
FusedCFuncDefNode
(
node
,
self
.
env_stack
[
-
1
])
self
.
visitchildren
(
node
)
else
:
node
.
body
.
analyse_declarations
(
lenv
)
self
.
env_stack
.
append
(
lenv
)
self
.
visitchildren
(
node
)
self
.
env_stack
.
pop
()
self
.
seen_vars_stack
.
pop
()
return
node
...
...
Cython/Compiler/Parsing.py
View file @
47ce63c9
...
...
@@ -2572,6 +2572,24 @@ 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_ctypedef_statement
(
s
,
ctx
):
# s.sy == 'ctypedef'
pos
=
s
.
position
()
...
...
@@ -2588,17 +2606,37 @@ def p_ctypedef_statement(s, ctx):
return
p_c_enum_definition
(
s
,
pos
,
ctx
)
else
:
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
:
base_type
=
p_c_base_type
(
s
,
nonempty
=
1
)
if
base_type
.
name
is
None
:
s
.
error
(
"Syntax error in ctypedef statement"
)
declarator
=
p_c_declarator
(
s
,
ctx
,
is_type
=
1
,
nonempty
=
1
)
s
.
expect_newline
(
"Syntax error in ctypedef statement"
)
return
Nodes
.
CTypeDefNode
(
pos
,
base_type
=
base_type
,
declarator
=
declarator
,
visibility
=
visibility
,
api
=
api
,
in_pxd
=
ctx
.
level
==
'module_pxd'
)
declarator
=
p_c_declarator
(
s
,
ctx
,
is_type
=
1
,
nonempty
=
1
)
s
.
expect_newline
(
"Syntax error in ctypedef statement"
)
return
Nodes
.
CTypeDefNode
(
pos
,
base_type
=
base_type
,
declarator
=
declarator
,
visibility
=
visibility
,
api
=
api
,
in_pxd
=
ctx
.
level
==
'module_pxd'
)
def
p_decorators
(
s
):
decorators
=
[]
...
...
Cython/Compiler/PyrexTypes.py
View file @
47ce63c9
...
...
@@ -2,6 +2,8 @@
# Pyrex - Types
#
import
cython
from
Code
import
UtilityCode
import
StringEncoding
import
Naming
...
...
@@ -12,6 +14,9 @@ class BaseType(object):
#
# Base class for all Pyrex types including pseudo-types.
# List of attribute names of any subtypes
subtypes
=
[]
def
can_coerce_to_pyobject
(
self
,
env
):
return
False
...
...
@@ -27,6 +32,42 @@ class BaseType(object):
else
:
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
):
#
# Base class for all Pyrex types.
...
...
@@ -195,7 +236,8 @@ class CTypedefType(BaseType):
to_py_utility_code
=
None
from_py_utility_code
=
None
subtypes
=
[
'typedef_base_type'
]
def
__init__
(
self
,
name
,
base_type
,
cname
,
is_external
=
0
):
assert
not
base_type
.
is_complex
...
...
@@ -314,6 +356,9 @@ class BufferType(BaseType):
is_buffer
=
1
writable
=
True
subtypes
=
[
'dtype'
]
def
__init__
(
self
,
base
,
dtype
,
ndim
,
mode
,
negative_indices
,
cast
):
self
.
base
=
base
self
.
dtype
=
dtype
...
...
@@ -345,7 +390,7 @@ class PyObjectType(PyrexType):
buffer_defaults
=
None
is_extern
=
False
is_subclassed
=
False
def
__str__
(
self
):
return
"Python object"
...
...
@@ -618,6 +663,45 @@ class CType(PyrexType):
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
):
#
# C "void" type
...
...
@@ -1531,7 +1615,9 @@ class CArrayType(CType):
# size integer or None Number of elements
is_array
=
1
subtypes
=
[
'base_type'
]
def
__init__
(
self
,
base_type
,
size
):
self
.
base_type
=
base_type
self
.
size
=
size
...
...
@@ -1577,6 +1663,8 @@ class CPtrType(CType):
is_ptr
=
1
default_value
=
"0"
subtypes
=
[
'base_type'
]
def
__init__
(
self
,
base_type
):
self
.
base_type
=
base_type
...
...
@@ -1675,7 +1763,9 @@ class CFuncType(CType):
is_cfunction
=
1
original_sig
=
None
subtypes
=
[
'return_type'
,
'args'
]
def
__init__
(
self
,
return_type
,
args
,
has_varargs
=
0
,
exception_value
=
None
,
exception_check
=
0
,
calling_convention
=
""
,
nogil
=
0
,
with_gil
=
0
,
is_overridable
=
0
,
optional_arg_count
=
0
,
...
...
@@ -1691,7 +1781,7 @@ class CFuncType(CType):
self
.
with_gil
=
with_gil
self
.
is_overridable
=
is_overridable
self
.
templates
=
templates
def
__repr__
(
self
):
arg_reprs
=
map
(
repr
,
self
.
args
)
if
self
.
has_varargs
:
...
...
@@ -1915,7 +2005,7 @@ class CFuncType(CType):
return
self
.
op_arg_struct
.
base_type
.
scope
.
lookup
(
arg_name
).
cname
class
CFuncTypeArg
(
object
):
class
CFuncTypeArg
(
BaseType
):
# name string
# cname string
# type PyrexType
...
...
@@ -1926,6 +2016,8 @@ class CFuncTypeArg(object):
or_none
=
False
accept_none
=
True
subtypes
=
[
'type'
]
def
__init__
(
self
,
name
,
type
,
pos
,
cname
=
None
):
self
.
name
=
name
if
cname
is
not
None
:
...
...
@@ -2478,7 +2570,7 @@ def is_promotion(src_type, dst_type):
return
src_type
.
is_float
and
src_type
.
rank
<=
dst_type
.
rank
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
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):
possibilities
=
[]
bad_types
=
[]
needed_coercions
=
{}
for
func
,
func_type
in
candidates
:
score
=
[
0
,
0
,
0
]
for
i
in
range
(
min
(
len
(
args
),
len
(
func_type
.
args
))):
src_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
):
pass
# score 0
elif
is_promotion
(
src_type
,
dst_type
):
...
...
@@ -2567,18 +2680,28 @@ def best_match(args, functions, pos=None):
break
else
:
possibilities
.
append
((
score
,
func
))
# so we can sort it
if
possibilities
:
possibilities
.
sort
()
if
len
(
possibilities
)
>
1
and
possibilities
[
0
][
0
]
==
possibilities
[
1
][
0
]:
if
pos
is
not
None
:
error
(
pos
,
"ambiguous overloaded method"
)
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
len
(
bad_types
)
==
1
:
error
(
pos
,
bad_types
[
0
][
1
])
else
:
error
(
pos
,
"no suitable method found"
)
return
None
def
widest_numeric_type
(
type1
,
type2
):
...
...
Cython/Compiler/Symtab.py
View file @
47ce63c9
...
...
@@ -176,6 +176,7 @@ class Entry(object):
buffer_aux = None
prev_entry = None
might_overflow = 0
fused_cfunction = None
def __init__(self, name, cname, type, pos = None, init = None):
self.name = name
...
...
@@ -241,6 +242,7 @@ class Scope(object):
scope_prefix = ""
in_cinclude = 0
nogil = 0
fused_to_specific = None
def __init__(self, name, outer_scope, parent_scope):
# The outer_scope is the next scope in the lookup chain.
...
...
@@ -279,6 +281,9 @@ class Scope(object):
self.return_type = None
self.id_counters = {}
def __deepcopy__(self, memo):
return self
def start_branching(self, pos):
self.control_flow = self.control_flow.start_branch(pos)
...
...
@@ -677,6 +682,8 @@ class Scope(object):
def lookup_type(self, name):
entry = self.lookup(name)
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
def lookup_operator(self, operator, operands):
...
...
Cython/Shadow.py
View file @
47ce63c9
...
...
@@ -225,6 +225,30 @@ class typedef(CythonType):
value
=
cast
(
self
.
_basetype
,
*
arg
)
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
...
...
@@ -277,3 +301,5 @@ for t in int_types + float_types + complex_types + other_types:
void
=
typedef
(
None
)
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