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
0527db06
Commit
0527db06
authored
Nov 03, 2014
by
Robert Bradshaw
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ctuple'
parents
28a78cb2
2c104e67
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
698 additions
and
94 deletions
+698
-94
CHANGES.rst
CHANGES.rst
+2
-0
Cython/Compiler/Buffer.py
Cython/Compiler/Buffer.py
+4
-4
Cython/Compiler/Code.py
Cython/Compiler/Code.py
+1
-1
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+105
-30
Cython/Compiler/FusedNode.py
Cython/Compiler/FusedNode.py
+2
-2
Cython/Compiler/MemoryView.py
Cython/Compiler/MemoryView.py
+6
-6
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+12
-8
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+160
-9
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+1
-1
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+13
-1
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+161
-27
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+17
-2
Cython/Utility/TypeConversion.c
Cython/Utility/TypeConversion.c
+49
-0
tests/run/arrayassign.pyx
tests/run/arrayassign.pyx
+18
-0
tests/run/ctuple.pyx
tests/run/ctuple.pyx
+142
-0
tests/run/type_inference.pyx
tests/run/type_inference.pyx
+5
-3
No files found.
CHANGES.rst
View file @
0527db06
...
...
@@ -47,6 +47,8 @@ Features added
* ``PySlice_*()`` C-API functions are available from the ``cpython.slice``
module.
* Anonymous C tuple types can be declared as (ctype1, ctype2, ...).
* Allow arrays of C++ classes.
Bugs fixed
...
...
Cython/Compiler/Buffer.py
View file @
0527db06
...
...
@@ -256,7 +256,7 @@ class BufferEntry(object):
defcode
=
code
.
globalstate
[
'utility_code_def'
]
funcgen
(
protocode
,
defcode
,
name
=
funcname
,
nd
=
nd
)
buf_ptr_type_code
=
self
.
buf_ptr_type
.
declaration_code
(
""
)
buf_ptr_type_code
=
self
.
buf_ptr_type
.
empty_declaration_code
(
)
ptrcode
=
"%s(%s, %s, %s)"
%
(
funcname
,
buf_ptr_type_code
,
self
.
buf_ptr
,
", "
.
join
(
params
))
return
ptrcode
...
...
@@ -627,7 +627,7 @@ def mangle_dtype_name(dtype):
prefix
=
"nn_"
else
:
prefix
=
""
type_decl
=
dtype
.
declaration_code
(
""
)
type_decl
=
dtype
.
empty_declaration_code
(
)
type_decl
=
type_decl
.
replace
(
" "
,
"_"
)
return
prefix
+
type_decl
.
replace
(
"["
,
"_"
).
replace
(
"]"
,
"_"
)
...
...
@@ -665,7 +665,7 @@ def get_type_information_cname(code, dtype, maxdepth=None):
complex_possible
=
dtype
.
is_struct_or_union
and
dtype
.
can_be_complex
()
declcode
=
dtype
.
declaration_code
(
""
)
declcode
=
dtype
.
empty_declaration_code
(
)
if
dtype
.
is_simple_buffer_dtype
():
structinfo_name
=
"NULL"
elif
dtype
.
is_struct
:
...
...
@@ -678,7 +678,7 @@ def get_type_information_cname(code, dtype, maxdepth=None):
typecode
.
putln
(
"static __Pyx_StructField %s[] = {"
%
structinfo_name
,
safe
=
True
)
for
f
,
typeinfo
in
zip
(
fields
,
types
):
typecode
.
putln
(
' {&%s, "%s", offsetof(%s, %s)},'
%
(
typeinfo
,
f
.
name
,
dtype
.
declaration_code
(
""
),
f
.
cname
),
safe
=
True
)
(
typeinfo
,
f
.
name
,
dtype
.
empty_declaration_code
(
),
f
.
cname
),
safe
=
True
)
typecode
.
putln
(
' {NULL, NULL, 0}'
,
safe
=
True
)
typecode
.
putln
(
"};"
,
safe
=
True
)
else
:
...
...
Cython/Compiler/Code.py
View file @
0527db06
...
...
@@ -369,7 +369,7 @@ class UtilityCode(UtilityCodeBase):
def specialize(self, pyrex_type=None, **data):
# Dicts aren't hashable...
if pyrex_type is not None:
data['type'] = pyrex_type.
declaration_code(''
)
data['type'] = pyrex_type.
empty_declaration_code(
)
data['type_name'] = pyrex_type.specialization_name()
key = tuple(sorted(data.items()))
try:
...
...
Cython/Compiler/ExprNodes.py
View file @
0527db06
...
...
@@ -819,6 +819,10 @@ class ExprNode(Node):
return
self
elif
type
.
is_pyobject
or
type
.
is_int
or
type
.
is_ptr
or
type
.
is_float
:
return
CoerceToBooleanNode
(
self
,
env
)
elif
type
.
is_ctuple
:
bool_value
=
len
(
type
.
components
)
==
0
return
BoolNode
(
self
.
pos
,
value
=
bool_value
,
constant_result
=
bool_value
)
else
:
error
(
self
.
pos
,
"Type '%s' not acceptable as a boolean"
%
type
)
return
self
...
...
@@ -1556,7 +1560,7 @@ class NewExprNode(AtomicExprNode):
pass
def
calculate_result_code
(
self
):
return
"new "
+
self
.
class_type
.
declaration_code
(
""
)
return
"new "
+
self
.
class_type
.
empty_declaration_code
(
)
class
NameNode
(
AtomicExprNode
):
...
...
@@ -2919,6 +2923,12 @@ class IndexNode(ExprNode):
return
item_type
elif
base_type
.
is_ptr
or
base_type
.
is_array
:
return
base_type
.
base_type
elif
base_type
.
is_ctuple
and
isinstance
(
self
.
index
,
IntNode
):
index
=
self
.
index
.
constant_result
if
index
<
0
:
index
+=
base_type
.
size
if
0
<=
index
<
base_type
.
size
:
return
base_type
.
components
[
index
]
if
base_type
.
is_cpp_class
:
class
FakeOperand
:
...
...
@@ -3254,6 +3264,21 @@ class IndexNode(ExprNode):
error
(
self
.
pos
,
"Wrong number of template arguments: expected %s, got %s"
%
(
(
len
(
base_type
.
templates
),
len
(
self
.
type_indices
))))
self
.
type
=
base_type
.
specialize
(
dict
(
zip
(
base_type
.
templates
,
self
.
type_indices
)))
elif
base_type
.
is_ctuple
:
if
isinstance
(
self
.
index
,
IntNode
):
index
=
self
.
index
.
constant_result
if
-
base_type
.
size
<=
index
<
base_type
.
size
:
if
index
<
0
:
index
+=
base_type
.
size
self
.
type
=
base_type
.
components
[
index
]
else
:
error
(
self
.
pos
,
"Index %s out of bounds for '%s'"
%
(
index
,
base_type
))
self
.
type
=
PyrexTypes
.
error_type
else
:
self
.
base
=
self
.
base
.
coerce_to_pyobject
(
env
)
return
self
.
analyse_base_and_index_types
(
env
,
getting
=
getting
,
setting
=
setting
,
analyse_base
=
False
)
else
:
error
(
self
.
pos
,
"Attempting to index non-array type '%s'"
%
...
...
@@ -3435,7 +3460,12 @@ class IndexNode(ExprNode):
elif
self
.
base
.
type
.
is_cfunction
:
return
"%s<%s>"
%
(
self
.
base
.
result
(),
","
.
join
([
param
.
declaration_code
(
""
)
for
param
in
self
.
type_indices
]))
","
.
join
([
param
.
empty_declaration_code
()
for
param
in
self
.
type_indices
]))
elif
self
.
base
.
type
.
is_ctuple
:
index
=
self
.
index
.
constant_result
if
index
<
0
:
index
+=
self
.
base
.
type
.
size
return
"%s.f%s"
%
(
self
.
base
.
result
(),
index
)
else
:
if
(
self
.
type
.
is_ptr
or
self
.
type
.
is_array
)
and
self
.
type
==
self
.
base
.
type
:
error
(
self
.
pos
,
"Invalid use of pointer slice"
)
...
...
@@ -3453,7 +3483,7 @@ class IndexNode(ExprNode):
and
self
.
index
.
constant_result
>=
0
))
boundscheck
=
bool
(
code
.
globalstate
.
directives
[
'boundscheck'
])
return
", %s, %d, %s, %d, %d, %d"
%
(
self
.
original_index_type
.
declaration_code
(
""
),
self
.
original_index_type
.
empty_declaration_code
(
),
self
.
original_index_type
.
signed
and
1
or
0
,
self
.
original_index_type
.
to_py_function
,
is_list
,
wraparound
,
boundscheck
)
...
...
@@ -4365,7 +4395,7 @@ class CallNode(ExprNode):
constructor
=
type
.
scope
.
lookup
(
"<init>"
)
self
.
function
=
RawCNameExprNode
(
self
.
function
.
pos
,
constructor
.
type
)
self
.
function
.
entry
=
constructor
self
.
function
.
set_cname
(
type
.
declaration_code
(
""
))
self
.
function
.
set_cname
(
type
.
empty_declaration_code
(
))
self
.
analyse_c_function_call
(
env
)
self
.
type
=
type
return
True
...
...
@@ -4447,7 +4477,7 @@ class SimpleCallNode(CallNode):
func_type
=
self
.
function_type
()
if
func_type
.
is_pyobject
:
self
.
arg_tuple
=
TupleNode
(
self
.
pos
,
args
=
self
.
args
)
self
.
arg_tuple
=
self
.
arg_tuple
.
analyse_types
(
env
)
self
.
arg_tuple
=
self
.
arg_tuple
.
analyse_types
(
env
)
.
coerce_to_pyobject
(
env
)
self
.
args
=
None
if
func_type
is
Builtin
.
type_type
and
function
.
is_name
and
\
function
.
entry
and
\
...
...
@@ -6070,6 +6100,10 @@ class SequenceNode(ExprNode):
', '
.
join
([
arg
.
py_result
()
for
arg
in
self
.
args
]),
code
.
error_goto_if_null
(
target
,
self
.
pos
)))
code
.
put_gotref
(
target
)
elif
self
.
type
.
is_ctuple
:
for
i
,
arg
in
enumerate
(
self
.
args
):
code
.
putln
(
"%s.f%s = %s;"
%
(
target
,
i
,
arg
.
result
()))
else
:
# build the tuple/list step by step, potentially multiplying it as we go
if
self
.
type
is
Builtin
.
list_type
:
...
...
@@ -6443,13 +6477,32 @@ class TupleNode(SequenceNode):
gil_message
=
"Constructing Python tuple"
def
infer_type
(
self
,
env
):
if
self
.
mult_factor
or
not
self
.
args
:
return
tuple_type
arg_types
=
[
arg
.
infer_type
(
env
)
for
arg
in
self
.
args
]
if
any
(
type
.
is_pyobject
or
type
.
is_unspecified
or
type
.
is_fused
for
type
in
arg_types
):
return
tuple_type
else
:
type
=
PyrexTypes
.
c_tuple_type
(
arg_types
)
env
.
declare_tuple_type
(
self
.
pos
,
type
)
return
type
def
analyse_types
(
self
,
env
,
skip_children
=
False
):
if
len
(
self
.
args
)
==
0
:
node
=
self
node
.
is_temp
=
False
node
.
is_literal
=
True
self
.
is_temp
=
False
self
.
is_literal
=
True
return
self
else
:
if
not
skip_children
:
self
.
args
=
[
arg
.
analyse_types
(
env
)
for
arg
in
self
.
args
]
if
not
self
.
mult_factor
and
not
any
(
arg
.
type
.
is_pyobject
or
arg
.
type
.
is_fused
for
arg
in
self
.
args
):
self
.
type
=
PyrexTypes
.
c_tuple_type
(
arg
.
type
for
arg
in
self
.
args
)
env
.
declare_tuple_type
(
self
.
pos
,
self
.
type
)
self
.
is_temp
=
1
return
self
else
:
node
=
SequenceNode
.
analyse_types
(
self
,
env
,
skip_children
)
node
=
SequenceNode
.
analyse_types
(
self
,
env
,
skip_children
=
True
)
for
child
in
node
.
args
:
if
not
child
.
is_literal
:
break
...
...
@@ -6465,6 +6518,21 @@ class TupleNode(SequenceNode):
node
.
is_partly_literal
=
True
return
node
def
coerce_to
(
self
,
dst_type
,
env
):
if
self
.
type
.
is_ctuple
:
if
dst_type
.
is_ctuple
and
self
.
type
.
size
==
dst_type
.
size
:
if
self
.
type
==
dst_type
:
return
self
coerced_args
=
[
arg
.
coerce_to
(
type
,
env
)
for
arg
,
type
in
zip
(
self
.
args
,
dst_type
.
components
)]
return
TupleNode
(
self
.
pos
,
args
=
coerced_args
,
type
=
dst_type
,
is_temp
=
1
)
elif
dst_type
is
tuple_type
or
dst_type
is
py_object_type
:
coerced_args
=
[
arg
.
coerce_to_pyobject
(
env
)
for
arg
in
self
.
args
]
return
TupleNode
(
self
.
pos
,
args
=
coerced_args
,
type
=
tuple_type
,
is_temp
=
1
).
analyse_types
(
env
,
skip_children
=
True
)
else
:
return
self
.
coerce_to_pyobject
(
env
).
coerce_to
(
dst_type
,
env
)
else
:
return
SequenceNode
.
coerce_to
(
self
,
dst_type
,
env
)
def
is_simple
(
self
):
# either temp or constant => always simple
return
True
...
...
@@ -6515,6 +6583,7 @@ class TupleNode(SequenceNode):
self
.
generate_sequence_packing_code
(
code
)
code
.
put_giveref
(
self
.
py_result
())
else
:
self
.
type
.
entry
.
used
=
True
self
.
generate_sequence_packing_code
(
code
)
...
...
@@ -8029,6 +8098,9 @@ class DefaultsTupleNode(TupleNode):
args
.
append
(
arg
)
super
(
DefaultsTupleNode
,
self
).
__init__
(
pos
,
args
=
args
)
def
analyse_types
(
self
,
env
,
skip_children
=
False
):
return
super
(
DefaultsTupleNode
,
self
).
analyse_types
(
env
,
skip_children
).
coerce_to_pyobject
(
env
)
class
DefaultsKwDictNode
(
DictNode
):
# CyFunction's __kwdefaults__ dict
...
...
@@ -8382,7 +8454,7 @@ class UnopNode(ExprNode):
return
self
.
operand
.
check_const
()
def
is_py_operation
(
self
):
return
self
.
operand
.
type
.
is_pyobject
return
self
.
operand
.
type
.
is_pyobject
or
self
.
operand
.
type
.
is_ctuple
def
nogil_check
(
self
,
env
):
if
self
.
is_py_operation
():
...
...
@@ -8949,7 +9021,7 @@ class CythonArrayNode(ExprNode):
shapes_temp
=
code
.
funcstate
.
allocate_temp
(
py_object_type
,
True
)
format_temp
=
code
.
funcstate
.
allocate_temp
(
py_object_type
,
True
)
itemsize
=
"sizeof(%s)"
%
dtype
.
declaration_code
(
""
)
itemsize
=
"sizeof(%s)"
%
dtype
.
empty_declaration_code
(
)
type_info
=
Buffer
.
get_type_information_cname
(
code
,
dtype
)
if
self
.
operand
.
type
.
is_ptr
:
...
...
@@ -9069,7 +9141,7 @@ class SizeofTypeNode(SizeofNode):
# we want the size of the actual struct
arg_code
=
self
.
arg_type
.
declaration_code
(
""
,
deref
=
1
)
else
:
arg_code
=
self
.
arg_type
.
declaration_code
(
""
)
arg_code
=
self
.
arg_type
.
empty_declaration_code
(
)
return
"(sizeof(%s))"
%
arg_code
...
...
@@ -9236,7 +9308,7 @@ class BinopNode(ExprNode):
return
self
.
is_py_operation_types
(
self
.
operand1
.
type
,
self
.
operand2
.
type
)
def
is_py_operation_types
(
self
,
type1
,
type2
):
return
type1
.
is_pyobject
or
type2
.
is_pyobject
return
type1
.
is_pyobject
or
type2
.
is_pyobject
or
type1
.
is_ctuple
or
type2
.
is_ctuple
def
is_cpp_operation
(
self
):
return
(
self
.
operand1
.
type
.
is_cpp_class
...
...
@@ -9697,12 +9769,12 @@ class DivNode(NumBinopNode):
# explicitly signed, no runtime check needed
minus1_check
=
'unlikely(%s == -1)'
%
self
.
operand2
.
result
()
else
:
type_of_op2
=
self
.
operand2
.
type
.
declaration_code
(
''
)
type_of_op2
=
self
.
operand2
.
type
.
empty_declaration_code
(
)
minus1_check
=
'(!(((%s)-1) > 0)) && unlikely(%s == (%s)-1)'
%
(
type_of_op2
,
self
.
operand2
.
result
(),
type_of_op2
)
code
.
putln
(
"else if (sizeof(%s) == sizeof(long) && %s "
" && unlikely(UNARY_NEG_WOULD_OVERFLOW(%s))) {"
%
(
self
.
type
.
declaration_code
(
''
),
self
.
type
.
empty_declaration_code
(
),
minus1_check
,
self
.
operand1
.
result
()))
code
.
put_ensure_gil
()
...
...
@@ -9850,11 +9922,11 @@ class PowNode(NumBinopNode):
elif
self
.
type
.
is_float
:
self
.
pow_func
=
"pow"
+
self
.
type
.
math_h_modifier
elif
self
.
type
.
is_int
:
self
.
pow_func
=
"__Pyx_pow_%s"
%
self
.
type
.
declaration_code
(
''
).
replace
(
' '
,
'_'
)
self
.
pow_func
=
"__Pyx_pow_%s"
%
self
.
type
.
empty_declaration_code
(
).
replace
(
' '
,
'_'
)
env
.
use_utility_code
(
int_pow_utility_code
.
specialize
(
func_name
=
self
.
pow_func
,
type
=
self
.
type
.
declaration_code
(
''
),
type
=
self
.
type
.
empty_declaration_code
(
),
signed
=
self
.
type
.
signed
and
1
or
0
))
elif
not
self
.
type
.
is_error
:
error
(
self
.
pos
,
"got unexpected types for C power operator: %s, %s"
%
...
...
@@ -10355,6 +10427,9 @@ class CmpNode(object):
if
new_common_type
is
None
:
# fall back to generic type compatibility tests
if
type1
==
type2
:
if
type1
.
is_ctuple
:
new_common_type
=
py_object_type
else
:
new_common_type
=
type1
elif
type1
.
is_pyobject
or
type2
.
is_pyobject
:
if
type2
.
is_numeric
or
type2
.
is_string
:
...
...
Cython/Compiler/FusedNode.py
View file @
0527db06
...
...
@@ -481,7 +481,7 @@ class FusedCFuncDefNode(StatListNode):
# self._dtype_name(dtype)))
decl_code
.
putln
(
'ctypedef %s %s "%s"'
%
(
dtype
.
resolve
(),
self
.
_dtype_name
(
dtype
),
dtype
.
declaration_code
(
""
)))
dtype
.
empty_declaration_code
(
)))
if
buffer_type
.
dtype
.
is_int
:
if
str
(
dtype
)
not
in
seen_int_dtypes
:
...
...
@@ -729,7 +729,7 @@ class FusedCFuncDefNode(StatListNode):
if
self
.
py_func
:
args
=
[
CloneNode
(
default
)
for
default
in
defaults
if
default
]
self
.
defaults_tuple
=
TupleNode
(
self
.
pos
,
args
=
args
)
self
.
defaults_tuple
=
self
.
defaults_tuple
.
analyse_types
(
env
,
skip_children
=
True
)
self
.
defaults_tuple
=
self
.
defaults_tuple
.
analyse_types
(
env
,
skip_children
=
True
)
.
coerce_to_pyobject
(
env
)
self
.
defaults_tuple
=
ProxyNode
(
self
.
defaults_tuple
)
self
.
code_object
=
ProxyNode
(
self
.
specialized_pycfuncs
[
0
].
code_object
)
...
...
Cython/Compiler/MemoryView.py
View file @
0527db06
...
...
@@ -237,7 +237,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
def
_generate_buffer_lookup_code
(
self
,
code
,
axes
,
cast_result
=
True
):
bufp
=
self
.
buf_ptr
type_decl
=
self
.
type
.
dtype
.
declaration_code
(
""
)
type_decl
=
self
.
type
.
dtype
.
empty_declaration_code
(
)
for
dim
,
index
,
access
,
packing
in
axes
:
shape
=
"%s.shape[%d]"
%
(
self
.
cname
,
dim
)
...
...
@@ -467,7 +467,7 @@ def copy_broadcast_memview_src_to_dst(src, dst, code):
def
get_1d_fill_scalar_func
(
type
,
code
):
dtype
=
type
.
dtype
type_decl
=
dtype
.
declaration_code
(
""
)
type_decl
=
dtype
.
empty_declaration_code
(
)
dtype_name
=
mangle_dtype_name
(
dtype
)
context
=
dict
(
dtype_name
=
dtype_name
,
type_decl
=
type_decl
)
...
...
@@ -482,8 +482,8 @@ def assign_scalar(dst, scalar, code):
"""
verify_direct_dimensions
(
dst
)
dtype
=
dst
.
type
.
dtype
type_decl
=
dtype
.
declaration_code
(
""
)
slice_decl
=
dst
.
type
.
declaration_code
(
""
)
type_decl
=
dtype
.
empty_declaration_code
(
)
slice_decl
=
dst
.
type
.
empty_declaration_code
(
)
code
.
begin_block
()
code
.
putln
(
"%s __pyx_temp_scalar = %s;"
%
(
type_decl
,
scalar
.
result
()))
...
...
@@ -527,7 +527,7 @@ class ContigSliceIter(SliceIter):
code
=
self
.
code
code
.
begin_block
()
type_decl
=
self
.
slice_type
.
dtype
.
declaration_code
(
""
)
type_decl
=
self
.
slice_type
.
dtype
.
empty_declaration_code
(
)
total_size
=
' * '
.
join
(
"%s.shape[%d]"
%
(
self
.
slice_temp
,
i
)
for
i
in
range
(
self
.
ndim
))
...
...
@@ -613,7 +613,7 @@ def get_copy_new_utility(pos, from_memview, to_memview):
context
=
dict
(
context
,
mode
=
mode
,
dtype_decl
=
to_memview
.
dtype
.
declaration_code
(
''
),
dtype_decl
=
to_memview
.
dtype
.
empty_declaration_code
(
),
contig_flag
=
contig_flag
,
ndim
=
to_memview
.
ndim
,
func_cname
=
copy_c_or_fortran_cname
(
to_memview
),
...
...
Cython/Compiler/ModuleNode.py
View file @
0527db06
...
...
@@ -251,7 +251,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
%
(
entry
.
name
,
cname
,
sig
))
for
entry
in
api_vars
:
cname
=
env
.
mangle
(
Naming
.
varptr_prefix
,
entry
.
name
)
sig
=
entry
.
type
.
declaration_code
(
""
)
sig
=
entry
.
type
.
empty_declaration_code
(
)
h_code
.
putln
(
'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;'
%
(
entry
.
name
,
cname
,
sig
))
...
...
@@ -721,6 +721,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
pass
elif
type
.
is_struct_or_union
or
type
.
is_cpp_class
:
self
.
generate_struct_union_predeclaration
(
entry
,
code
)
elif
type
.
is_ctuple
and
entry
.
used
:
self
.
generate_struct_union_predeclaration
(
entry
.
type
.
struct_entry
,
code
)
elif
type
.
is_extension_type
:
self
.
generate_objstruct_predeclaration
(
type
,
code
)
# Actual declarations
...
...
@@ -734,6 +736,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self
.
generate_enum_definition
(
entry
,
code
)
elif
type
.
is_struct_or_union
:
self
.
generate_struct_union_definition
(
entry
,
code
)
elif
type
.
is_ctuple
and
entry
.
used
:
self
.
generate_struct_union_definition
(
entry
.
type
.
struct_entry
,
code
)
elif
type
.
is_cpp_class
:
self
.
generate_cpp_class_definition
(
entry
,
code
)
elif
type
.
is_extension_type
:
...
...
@@ -776,7 +780,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def
generate_struct_union_predeclaration
(
self
,
entry
,
code
):
type
=
entry
.
type
if
type
.
is_cpp_class
and
type
.
templates
:
code
.
putln
(
"template <typename %s>"
%
", typename "
.
join
([
T
.
declaration_code
(
""
)
for
T
in
type
.
templates
]))
code
.
putln
(
"template <typename %s>"
%
", typename "
.
join
([
T
.
empty_declaration_code
(
)
for
T
in
type
.
templates
]))
code
.
putln
(
self
.
sue_predeclaration
(
type
,
type
.
kind
,
type
.
cname
))
def
sue_header_footer
(
self
,
type
,
kind
,
name
):
...
...
@@ -826,12 +830,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
scope
=
type
.
scope
if
scope
:
if
type
.
templates
:
code
.
putln
(
"template <class %s>"
%
", class "
.
join
([
T
.
declaration_code
(
""
)
for
T
in
type
.
templates
]))
code
.
putln
(
"template <class %s>"
%
", class "
.
join
([
T
.
empty_declaration_code
(
)
for
T
in
type
.
templates
]))
# Just let everything be public.
code
.
put
(
"struct %s"
%
type
.
cname
)
if
type
.
base_classes
:
base_class_decl
=
", public "
.
join
(
[
base_class
.
declaration_code
(
""
)
for
base_class
in
type
.
base_classes
])
[
base_class
.
empty_declaration_code
(
)
for
base_class
in
type
.
base_classes
])
code
.
put
(
" : public %s"
%
base_class_decl
)
code
.
putln
(
" {"
)
has_virtual_methods
=
False
...
...
@@ -1124,7 +1128,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code
.
putln
(
"%s = (%s)o;"
%
(
type
.
declaration_code
(
"p"
),
type
.
declaration_code
(
""
)))
type
.
empty_declaration_code
(
)))
def
generate_new_function
(
self
,
scope
,
code
,
cclass_entry
):
tp_slot
=
TypeSlots
.
ConstructorSlot
(
"tp_new"
,
'__new__'
)
...
...
@@ -1226,7 +1230,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for
entry
in
cpp_class_attrs
:
code
.
putln
(
"new((void*)&(p->%s)) %s();"
%
(
entry
.
cname
,
entry
.
type
.
declaration_code
(
""
)))
(
entry
.
cname
,
entry
.
type
.
empty_declaration_code
(
)))
for
entry
in
py_attrs
:
code
.
put_init_var_to_py_none
(
entry
,
"p->%s"
,
nanny
=
False
)
...
...
@@ -2427,7 +2431,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if
entries
:
env
.
use_utility_code
(
UtilityCode
.
load_cached
(
"VoidPtrExport"
,
"ImportExport.c"
))
for
entry
in
entries
:
signature
=
entry
.
type
.
declaration_code
(
""
)
signature
=
entry
.
type
.
empty_declaration_code
(
)
name
=
code
.
intern_identifier
(
entry
.
name
)
code
.
putln
(
'if (__Pyx_ExportVoidPtr(%s, (void *)&%s, "%s") < 0) %s'
%
(
name
,
entry
.
cname
,
signature
,
...
...
@@ -2495,7 +2499,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
cname
=
entry
.
cname
else
:
cname
=
module
.
mangle
(
Naming
.
varptr_prefix
,
entry
.
name
)
signature
=
entry
.
type
.
declaration_code
(
""
)
signature
=
entry
.
type
.
empty_declaration_code
(
)
code
.
putln
(
'if (__Pyx_ImportVoidPtr(%s, "%s", (void **)&%s, "%s") < 0) %s'
%
(
temp
,
entry
.
name
,
cname
,
signature
,
...
...
Cython/Compiler/Nodes.py
View file @
0527db06
...
...
@@ -832,7 +832,7 @@ class CArgDeclNode(Node):
if
self
.
base_type
.
is_basic_c_type
:
# char, short, long called "int"
type
=
self
.
base_type
.
analyse
(
env
,
could_be_name
=
True
)
arg_name
=
type
.
declaration_code
(
""
)
arg_name
=
type
.
empty_declaration_code
(
)
else
:
arg_name
=
self
.
base_type
.
name
self
.
declarator
.
name
=
EncodedString
(
arg_name
)
...
...
@@ -1165,6 +1165,25 @@ class CComplexBaseTypeNode(CBaseTypeNode):
return
type
class
CTupleBaseTypeNode
(
CBaseTypeNode
):
# components [CBaseTypeNode]
child_attrs
=
[
"components"
]
def
analyse
(
self
,
env
,
could_be_name
=
False
):
component_types
=
[]
for
c
in
self
.
components
:
type
=
c
.
analyse
(
env
)
if
type
.
is_pyobject
:
error
(
type_node
.
pos
,
"Tuple types can't (yet) contain Python objects."
)
return
PyrexType
.
error_type
component_types
.
append
(
type
)
type
=
PyrexTypes
.
c_tuple_type
(
component_types
)
entry
=
env
.
declare_tuple_type
(
self
.
pos
,
type
)
entry
.
used
=
True
return
type
class
FusedTypeNode
(
CBaseTypeNode
):
"""
Represents a fused type in a ctypedef statement:
...
...
@@ -1184,7 +1203,7 @@ class FusedTypeNode(CBaseTypeNode):
# Omit the typedef declaration that self.declarator would produce
entry
.
in_cinclude
=
True
def
analyse
(
self
,
env
):
def
analyse
(
self
,
env
,
could_be_name
=
False
):
types
=
[]
for
type_node
in
self
.
types
:
type
=
type_node
.
analyse_as_type
(
env
)
...
...
@@ -1793,7 +1812,7 @@ class FuncDefNode(StatNode, BlockNode):
slot_func_cname
=
'%s->tp_new'
%
lenv
.
scope_class
.
type
.
typeptr_cname
code
.
putln
(
"%s = (%s)%s(%s, %s, NULL);"
%
(
Naming
.
cur_scope_cname
,
lenv
.
scope_class
.
type
.
declaration_code
(
''
),
lenv
.
scope_class
.
type
.
empty_declaration_code
(
),
slot_func_cname
,
lenv
.
scope_class
.
type
.
typeptr_cname
,
Naming
.
empty_tuple
))
...
...
@@ -1815,12 +1834,12 @@ class FuncDefNode(StatNode, BlockNode):
if
self
.
is_cyfunction
:
code
.
putln
(
"%s = (%s) __Pyx_CyFunction_GetClosure(%s);"
%
(
outer_scope_cname
,
cenv
.
scope_class
.
type
.
declaration_code
(
''
),
cenv
.
scope_class
.
type
.
empty_declaration_code
(
),
Naming
.
self_cname
))
else
:
code
.
putln
(
"%s = (%s) %s;"
%
(
outer_scope_cname
,
cenv
.
scope_class
.
type
.
declaration_code
(
''
),
cenv
.
scope_class
.
type
.
empty_declaration_code
(
),
Naming
.
self_cname
))
if
lenv
.
is_passthrough
:
code
.
putln
(
"%s = %s;"
%
(
Naming
.
cur_scope_cname
,
outer_scope_cname
))
...
...
@@ -4657,7 +4676,7 @@ class AssignmentNode(StatNode):
def
analyse_expressions
(
self
,
env
):
node
=
self
.
analyse_types
(
env
)
if
isinstance
(
node
,
AssignmentNode
):
if
isinstance
(
node
,
AssignmentNode
)
and
not
isinstance
(
node
,
ParallelAssignmentNode
)
:
if
node
.
rhs
.
type
.
is_ptr
and
node
.
rhs
.
is_ephemeral
():
error
(
self
.
pos
,
"Storing unsafe C derivative of temporary Python reference"
)
return
node
...
...
@@ -4763,11 +4782,19 @@ class SingleAssignmentNode(AssignmentNode):
self
.
lhs
.
analyse_target_declaration
(
env
)
def
analyse_types
(
self
,
env
,
use_temp
=
0
):
from
.
import
ExprNodes
from
.
import
ExprNodes
,
UtilNodes
self
.
rhs
=
self
.
rhs
.
analyse_types
(
env
)
unrolled_assignment
=
self
.
unroll_rhs
(
env
)
if
unrolled_assignment
:
return
unrolled_assignment
self
.
lhs
=
self
.
lhs
.
analyse_target_types
(
env
)
self
.
lhs
.
gil_assignment_check
(
env
)
unrolled_assignment
=
self
.
unroll_lhs
(
env
)
if
unrolled_assignment
:
return
unrolled_assignment
if
self
.
lhs
.
memslice_broadcast
or
self
.
rhs
.
memslice_broadcast
:
self
.
lhs
.
memslice_broadcast
=
True
...
...
@@ -4801,6 +4828,130 @@ class SingleAssignmentNode(AssignmentNode):
self
.
rhs
=
rhs
return
self
def
unroll
(
self
,
node
,
target_size
,
env
):
from
.
import
ExprNodes
,
UtilNodes
if
node
.
type
.
is_ctuple
:
if
node
.
type
.
size
==
target_size
:
base
=
node
start_node
=
None
stop_node
=
None
step_node
=
None
check_node
=
None
else
:
error
(
self
.
pos
,
"Unpacking type %s requires exactly %s arguments."
%
(
node
.
type
,
node
.
type
.
size
))
return
elif
node
.
type
.
is_ptr
:
if
isinstance
(
node
,
ExprNodes
.
SliceIndexNode
):
base
=
node
.
base
start_node
=
node
.
start
if
start_node
:
start_node
=
start_node
.
coerce_to
(
PyrexTypes
.
c_py_ssize_t_type
,
env
)
stop_node
=
node
.
stop
if
stop_node
:
stop_node
=
stop_node
.
coerce_to
(
PyrexTypes
.
c_py_ssize_t_type
,
env
)
else
:
if
node
.
type
.
is_array
and
node
.
type
.
size
:
stop_node
=
ExprNodes
.
IntNode
(
pos
=
self
.
pos
,
value
=
str
(
rhs
.
type
.
size
))
else
:
error
(
self
.
pos
,
"C array iteration requires known end index"
)
return
step_node
=
None
#node.step
if
step_node
:
step_node
=
step_node
.
coerce_to
(
PyrexTypes
.
c_py_ssize_t_type
,
env
)
# TODO: Factor out SliceIndexNode.generate_slice_guard_code() for use here.
def
get_const
(
node
,
none_value
):
if
node
is
None
:
return
none_value
elif
node
.
has_constant_result
:
node
.
calculate_constant_result
()
return
node
.
constant_result
else
:
raise
ValueError
,
"Not a constant."
try
:
slice_size
=
(
get_const
(
stop_node
,
None
)
-
get_const
(
start_node
,
0
))
/
get_const
(
step_node
,
1
)
if
target_size
!=
slice_size
:
error
(
self
.
pos
,
"Assignment to/from slice of wrong length, expected %d, got %d"
%
(
slice_size
,
target_size
))
except
ValueError
:
error
(
self
.
pos
,
"C array assignment currently requires known endpoints"
)
return
check_node
=
None
else
:
return
else
:
return
items
=
[]
base_ref
=
UtilNodes
.
LetRefNode
(
base
)
refs
=
[
base_ref
]
if
start_node
:
start_node
=
UtilNodes
.
LetRefNode
(
start_node
)
refs
.
append
(
start_node
)
if
stop_node
:
stop_node
=
UtilNodes
.
LetRefNode
(
stop_node
)
refs
.
append
(
stop_node
)
if
step_node
:
step_node
=
UtilNodes
.
LetRefNode
(
step_node
)
refs
.
append
(
step_node
)
for
ix
in
range
(
target_size
):
ix_node
=
ExprNodes
.
IntNode
(
pos
=
self
.
pos
,
value
=
str
(
ix
))
if
step_node
is
not
None
:
ix_node
=
ExprNodes
.
MulNode
(
pos
=
self
.
pos
,
operator
=
'*'
,
operand1
=
step_node
,
operand2
=
ix_node
).
analyse_types
(
env
)
if
start_node
is
not
None
:
ix_node
=
ExprNodes
.
AddNode
(
pos
=
self
.
pos
,
operator
=
'+'
,
operand1
=
start_node
,
operand2
=
ix_node
).
analyse_types
(
env
)
items
.
append
(
ExprNodes
.
IndexNode
(
pos
=
self
.
pos
,
base
=
base_ref
,
index
=
ix_node
))
return
check_node
,
refs
,
items
def
unroll_assignments
(
self
,
refs
,
check_node
,
lhs_list
,
rhs_list
,
env
):
from
.
import
ExprNodes
,
UtilNodes
assignments
=
[]
for
lhs
,
rhs
in
zip
(
lhs_list
,
rhs_list
):
assignments
.
append
(
SingleAssignmentNode
(
pos
=
self
.
pos
,
lhs
=
lhs
,
rhs
=
rhs
,
first
=
self
.
first
))
all
=
ParallelAssignmentNode
(
pos
=
self
.
pos
,
stats
=
assignments
).
analyse_expressions
(
env
)
if
check_node
:
all
=
StatListNode
(
pos
=
self
.
pos
,
stats
=
[
check_node
,
all
])
for
ref
in
refs
:
all
=
UtilNodes
.
LetNode
(
ref
,
all
)
return
all
def
unroll_rhs
(
self
,
env
):
from
.
import
ExprNodes
,
UtilNodes
if
not
isinstance
(
self
.
lhs
,
ExprNodes
.
TupleNode
):
return
for
arg
in
self
.
lhs
.
args
:
if
arg
.
is_starred
:
return
unrolled
=
self
.
unroll
(
self
.
rhs
,
len
(
self
.
lhs
.
args
),
env
)
if
not
unrolled
:
return
check_node
,
refs
,
rhs
=
unrolled
return
self
.
unroll_assignments
(
refs
,
check_node
,
self
.
lhs
.
args
,
rhs
,
env
)
def
unroll_lhs
(
self
,
env
):
if
self
.
lhs
.
type
.
is_ctuple
:
# Handled directly.
return
from
.
import
ExprNodes
,
UtilNodes
if
not
isinstance
(
self
.
rhs
,
ExprNodes
.
TupleNode
):
return
unrolled
=
self
.
unroll
(
self
.
lhs
,
len
(
self
.
rhs
.
args
),
env
)
if
not
unrolled
:
return
check_node
,
refs
,
lhs
=
unrolled
return
self
.
unroll_assignments
(
refs
,
check_node
,
lhs
,
self
.
rhs
.
args
,
env
)
def
generate_rhs_evaluation_code
(
self
,
code
):
self
.
rhs
.
generate_evaluation_code
(
code
)
...
...
@@ -5471,7 +5622,7 @@ class AssertStatNode(StatNode):
# prevent tuple values from being interpreted as argument value tuples
from
.ExprNodes
import
TupleNode
value
=
TupleNode
(
value
.
pos
,
args
=
[
value
],
slow
=
True
)
self
.
value
=
value
.
analyse_types
(
env
,
skip_children
=
True
)
self
.
value
=
value
.
analyse_types
(
env
,
skip_children
=
True
)
.
coerce_to_pyobject
(
env
)
else
:
self
.
value
=
value
.
coerce_to_pyobject
(
env
)
return
self
...
...
@@ -7691,7 +7842,7 @@ class ParallelStatNode(StatNode, ParallelNode):
if
not
lastprivate
or
entry
.
type
.
is_pyobject
:
continue
type_decl
=
entry
.
type
.
declaration_code
(
""
)
type_decl
=
entry
.
type
.
empty_declaration_code
(
)
temp_cname
=
"__pyx_parallel_temp%d"
%
temp_count
private_cname
=
entry
.
cname
...
...
Cython/Compiler/Optimize.py
View file @
0527db06
...
...
@@ -2593,7 +2593,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
constant_result
=
orig_index_type
.
signed
and
1
or
0
,
type
=
PyrexTypes
.
c_int_type
),
ExprNodes
.
RawCNameExprNode
(
index
.
pos
,
PyrexTypes
.
c_void_type
,
orig_index_type
.
declaration_code
(
""
)),
orig_index_type
.
empty_declaration_code
(
)),
ExprNodes
.
RawCNameExprNode
(
index
.
pos
,
conversion_type
,
convert_func
)],
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
...
...
Cython/Compiler/Parsing.py
View file @
0527db06
...
...
@@ -2038,9 +2038,21 @@ def p_c_complex_base_type(s, templates = None):
s
.
next
()
base_type
=
p_c_base_type
(
s
,
templates
=
templates
)
declarator
=
p_c_declarator
(
s
,
empty
=
1
)
s
.
expect
(
')'
)
type_node
=
Nodes
.
CComplexBaseTypeNode
(
pos
,
base_type
=
base_type
,
declarator
=
declarator
)
if
s
.
sy
==
','
:
components
=
[
type_node
]
while
s
.
sy
==
','
:
s
.
next
()
if
s
.
sy
==
')'
:
break
base_type
=
p_c_base_type
(
s
,
templates
=
templates
)
declarator
=
p_c_declarator
(
s
,
empty
=
1
)
components
.
append
(
Nodes
.
CComplexBaseTypeNode
(
pos
,
base_type
=
base_type
,
declarator
=
declarator
))
type_node
=
Nodes
.
CTupleBaseTypeNode
(
pos
,
components
=
components
)
s
.
expect
(
')'
)
if
s
.
sy
==
'['
:
if
is_memoryviewslice_access
(
s
):
type_node
=
p_memoryviewslice_access
(
s
,
type_node
)
...
...
Cython/Compiler/PyrexTypes.py
View file @
0527db06
...
...
@@ -6,6 +6,7 @@ from __future__ import absolute_import
import
re
import
copy
import
re
from
.Code
import
UtilityCode
,
LazyUtilityCode
,
TempitaUtilityCode
from
.
import
StringEncoding
...
...
@@ -20,18 +21,24 @@ class BaseType(object):
# List of attribute names of any subtypes
subtypes
=
[]
_empty_declaration
=
None
def
can_coerce_to_pyobject
(
self
,
env
):
return
False
def
cast_code
(
self
,
expr_code
):
return
"((%s)%s)"
%
(
self
.
declaration_code
(
""
),
expr_code
)
return
"((%s)%s)"
%
(
self
.
empty_declaration_code
(),
expr_code
)
def
empty_declaration_code
(
self
):
if
self
.
_empty_declaration
is
None
:
self
.
_empty_declaration
=
self
.
declaration_code
(
''
)
return
self
.
_empty_declaration
def
specialization_name
(
self
):
# This is not entirely robust.
safe
=
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789'
all
=
[]
for
c
in
self
.
declaration_code
(
""
).
replace
(
"unsigned "
,
"unsigned_"
).
replace
(
"long long"
,
"long_long"
).
replace
(
" "
,
"__"
):
for
c
in
self
.
empty_declaration_code
(
).
replace
(
"unsigned "
,
"unsigned_"
).
replace
(
"long long"
,
"long_long"
).
replace
(
" "
,
"__"
):
if
c
in
safe
:
all
.
append
(
c
)
else
:
...
...
@@ -225,6 +232,7 @@ class PyrexType(BaseType):
is_returncode
=
0
is_error
=
0
is_buffer
=
0
is_ctuple
=
0
is_memoryviewslice
=
0
has_attributes
=
0
default_value
=
""
...
...
@@ -373,7 +381,7 @@ class CTypedefType(BaseType):
def
_create_utility_code
(
self
,
template_utility_code
,
template_function_name
):
type_name
=
self
.
typedef_cname
.
replace
(
" "
,
"_"
).
replace
(
"::"
,
"__"
)
type_name
=
type_identifier
(
self
.
typedef_cname
)
utility_code
=
template_utility_code
.
specialize
(
type
=
self
.
typedef_cname
,
TypeName
=
type_name
)
...
...
@@ -388,7 +396,7 @@ class CTypedefType(BaseType):
self
.
to_py_function
=
"__Pyx_PyInt_From_"
+
self
.
specialization_name
()
env
.
use_utility_code
(
TempitaUtilityCode
.
load
(
"CIntToPy"
,
"TypeConversion.c"
,
context
=
{
"TYPE"
:
self
.
declaration_code
(
''
),
context
=
{
"TYPE"
:
self
.
empty_declaration_code
(
),
"TO_PY_FUNCTION"
:
self
.
to_py_function
}))
return
True
elif
base_type
.
is_float
:
...
...
@@ -410,7 +418,7 @@ class CTypedefType(BaseType):
self
.
from_py_function
=
"__Pyx_PyInt_As_"
+
self
.
specialization_name
()
env
.
use_utility_code
(
TempitaUtilityCode
.
load
(
"CIntFromPy"
,
"TypeConversion.c"
,
context
=
{
"TYPE"
:
self
.
declaration_code
(
''
),
context
=
{
"TYPE"
:
self
.
empty_declaration_code
(
),
"FROM_PY_FUNCTION"
:
self
.
from_py_function
}))
return
True
elif
base_type
.
is_float
:
...
...
@@ -440,7 +448,7 @@ class CTypedefType(BaseType):
def
overflow_check_binop
(
self
,
binop
,
env
,
const_rhs
=
False
):
env
.
use_utility_code
(
UtilityCode
.
load
(
"Common"
,
"Overflow.c"
))
type
=
self
.
declaration_code
(
""
)
type
=
self
.
empty_declaration_code
(
)
name
=
self
.
specialization_name
()
if
binop
==
"lshift"
:
env
.
use_utility_code
(
TempitaUtilityCode
.
load
(
...
...
@@ -701,7 +709,7 @@ class MemoryViewSliceType(PyrexType):
buf_flag
=
self
.
flags
,
ndim
=
self
.
ndim
,
axes_specs
=
', '
.
join
(
self
.
axes_to_code
()),
dtype_typedecl
=
self
.
dtype
.
declaration_code
(
""
),
dtype_typedecl
=
self
.
dtype
.
empty_declaration_code
(
),
struct_nesting_depth
=
self
.
dtype
.
struct_nesting_depth
(),
c_or_f_flag
=
c_or_f_flag
,
funcname
=
funcname
,
...
...
@@ -753,7 +761,7 @@ class MemoryViewSliceType(PyrexType):
context
.
update
(
to_py_function
=
self
.
dtype
.
to_py_function
,
from_py_function
=
self
.
dtype
.
from_py_function
,
dtype
=
self
.
dtype
.
declaration_code
(
""
),
dtype
=
self
.
dtype
.
empty_declaration_code
(
),
error_condition
=
error_condition
,
)
...
...
@@ -1472,7 +1480,7 @@ class CIntType(CNumericType):
self
.
to_py_function
=
"__Pyx_PyInt_From_"
+
self
.
specialization_name
()
env
.
use_utility_code
(
TempitaUtilityCode
.
load
(
"CIntToPy"
,
"TypeConversion.c"
,
context
=
{
"TYPE"
:
self
.
declaration_code
(
''
),
context
=
{
"TYPE"
:
self
.
empty_declaration_code
(
),
"TO_PY_FUNCTION"
:
self
.
to_py_function
}))
return
True
...
...
@@ -1481,7 +1489,7 @@ class CIntType(CNumericType):
self
.
from_py_function
=
"__Pyx_PyInt_As_"
+
self
.
specialization_name
()
env
.
use_utility_code
(
TempitaUtilityCode
.
load
(
"CIntFromPy"
,
"TypeConversion.c"
,
context
=
{
"TYPE"
:
self
.
declaration_code
(
''
),
context
=
{
"TYPE"
:
self
.
empty_declaration_code
(
),
"FROM_PY_FUNCTION"
:
self
.
from_py_function
}))
return
True
...
...
@@ -1516,7 +1524,7 @@ class CIntType(CNumericType):
def
overflow_check_binop
(
self
,
binop
,
env
,
const_rhs
=
False
):
env
.
use_utility_code
(
UtilityCode
.
load
(
"Common"
,
"Overflow.c"
))
type
=
self
.
declaration_code
(
""
)
type
=
self
.
empty_declaration_code
(
)
name
=
self
.
specialization_name
()
if
binop
==
"lshift"
:
env
.
use_utility_code
(
TempitaUtilityCode
.
load
(
...
...
@@ -1807,7 +1815,7 @@ class CComplexType(CNumericType):
env
.
use_utility_code
(
utility_code
.
specialize
(
self
,
real_type
=
self
.
real_type
.
declaration_code
(
''
),
real_type
=
self
.
real_type
.
empty_declaration_code
(
),
m
=
self
.
funcsuffix
,
is_float
=
self
.
real_type
.
is_float
))
return
True
...
...
@@ -1828,7 +1836,7 @@ class CComplexType(CNumericType):
env
.
use_utility_code
(
utility_code
.
specialize
(
self
,
real_type
=
self
.
real_type
.
declaration_code
(
''
),
real_type
=
self
.
real_type
.
empty_declaration_code
(
),
m
=
self
.
funcsuffix
,
is_float
=
self
.
real_type
.
is_float
))
self
.
from_py_function
=
"__Pyx_PyComplex_As_"
+
self
.
specialization_name
()
...
...
@@ -2683,7 +2691,7 @@ class CFuncType(CType):
func_name
,
arg_code
,
trailer
)
def
signature_string
(
self
):
s
=
self
.
declaration_code
(
""
)
s
=
self
.
empty_declaration_code
(
)
return
s
def
signature_cast_string
(
self
):
...
...
@@ -3042,7 +3050,7 @@ class ToPyStructUtilityCode(object):
# This is a bit of a hack, we need a forward declaration
# due to the way things are ordered in the module...
if
self
.
forward_decl
:
proto
.
putln
(
self
.
type
.
declaration_code
(
''
)
+
';'
)
proto
.
putln
(
self
.
type
.
empty_declaration_code
(
)
+
';'
)
proto
.
putln
(
self
.
header
+
";"
)
def
inject_tree_and_scope_into
(
self
,
module_node
):
...
...
@@ -3171,8 +3179,8 @@ class CStructOrUnionType(CType):
if
len
(
fields
)
!=
2
:
return
False
a
,
b
=
fields
return
(
a
.
type
.
is_float
and
b
.
type
.
is_float
and
a
.
type
.
declaration_code
(
""
)
==
b
.
type
.
declaration_code
(
""
))
a
.
type
.
empty_declaration_code
(
)
==
b
.
type
.
empty_declaration_code
(
))
def
struct_nesting_depth
(
self
):
child_depths
=
[
x
.
type
.
struct_nesting_depth
()
...
...
@@ -3264,21 +3272,21 @@ class CppClassType(CType):
except_clause
=
"? %s"
%
except_clause
declarations
.
append
(
" ctypedef %s %s '%s'"
%
(
except_type
.
declaration_code
(
""
,
for_display
=
True
),
X
[
ix
],
T
.
declaration_code
(
""
)))
except_type
.
declaration_code
(
""
,
for_display
=
True
),
X
[
ix
],
T
.
empty_declaration_code
(
)))
else
:
except_clause
=
"*"
declarations
.
append
(
" ctypedef struct %s '%s':
\
n
pass"
%
(
X
[
ix
],
T
.
declaration_code
(
""
)))
X
[
ix
],
T
.
empty_declaration_code
(
)))
declarations
.
append
(
" cdef %s %s_from_py '%s' (object) except %s"
%
(
X
[
ix
],
X
[
ix
],
T
.
from_py_function
,
except_clause
))
if
self
.
cname
in
cpp_string_conversions
:
cls
=
'string'
tags
=
self
.
cname
.
replace
(
':'
,
'_'
),
tags
=
type_identifier
(
self
),
else
:
cls
=
self
.
cname
[
5
:]
cname
=
'__pyx_convert_%s_from_py_%s'
%
(
cls
,
'__
_
_'
.
join
(
tags
))
cname
=
'__pyx_convert_%s_from_py_%s'
%
(
cls
,
'__
and
_'
.
join
(
tags
))
context
=
{
'template_type_declarations'
:
'
\
n
'
.
join
(
declarations
),
'cname'
:
cname
,
...
...
@@ -3304,14 +3312,14 @@ class CppClassType(CType):
tags
.
append
(
T
.
specialization_name
())
declarations
.
append
(
" ctypedef struct %s '%s':
\
n
pass"
%
(
X
[
ix
],
T
.
declaration_code
(
""
)))
X
[
ix
],
T
.
empty_declaration_code
(
)))
declarations
.
append
(
" cdef object %s_to_py '%s' (%s)"
%
(
X
[
ix
],
T
.
to_py_function
,
X
[
ix
]))
if
self
.
cname
in
cpp_string_conversions
:
cls
=
'string'
prefix
=
'PyObject_'
# gets specialised by explicit type casts in CoerceToPyTypeNode
tags
=
self
.
cname
.
replace
(
':'
,
'_'
),
tags
=
type_identifier
(
self
),
else
:
cls
=
self
.
cname
[
5
:]
prefix
=
''
...
...
@@ -3331,6 +3339,17 @@ class CppClassType(CType):
def
is_template_type
(
self
):
return
self
.
templates
is
not
None
and
self
.
template_type
is
None
def
get_fused_types
(
self
,
result
=
None
,
seen
=
None
):
if
result
is
None
:
result
=
[]
seen
=
set
()
if
self
.
namespace
:
self
.
namespace
.
get_fused_types
(
result
,
seen
)
if
self
.
templates
:
for
T
in
self
.
templates
:
T
.
get_fused_types
(
result
,
seen
)
return
result
def
specialize_here
(
self
,
pos
,
template_values
=
None
):
if
not
self
.
is_template_type
():
error
(
pos
,
"'%s' type is not a template"
%
self
)
...
...
@@ -3363,16 +3382,16 @@ class CppClassType(CType):
# Need to do these *after* self.specializations[key] is set
# to avoid infinite recursion on circular references.
specialized
.
base_classes
=
[
b
.
specialize
(
values
)
for
b
in
self
.
base_classes
]
specialized
.
scope
=
self
.
scope
.
specialize
(
values
,
specialized
)
if
self
.
namespace
is
not
None
:
specialized
.
namespace
=
self
.
namespace
.
specialize
(
values
)
specialized
.
scope
=
self
.
scope
.
specialize
(
values
,
specialized
)
return
specialized
def
deduce_template_params
(
self
,
actual
):
if
self
==
actual
:
return
{}
# TODO(robertwb): Actual type equality.
elif
self
.
declaration_code
(
""
)
==
actual
.
template_type
.
declaration_code
(
""
):
elif
self
.
empty_declaration_code
()
==
actual
.
template_type
.
empty_declaration_code
(
):
return
reduce
(
merge_template_deductions
,
[
formal_param
.
deduce_template_params
(
actual_param
)
for
(
formal_param
,
actual_param
)
in
zip
(
self
.
templates
,
actual
.
templates
)],
...
...
@@ -3397,7 +3416,7 @@ class CppClassType(CType):
else
:
base_code
=
"%s%s"
%
(
self
.
cname
,
templates
)
if
self
.
namespace
is
not
None
:
base_code
=
"%s::%s"
%
(
self
.
namespace
.
declaration_code
(
''
),
base_code
)
base_code
=
"%s::%s"
%
(
self
.
namespace
.
empty_declaration_code
(
),
base_code
)
base_code
=
public_decl
(
base_code
,
dll_linkage
)
return
self
.
base_declaration_code
(
base_code
,
entity_code
)
...
...
@@ -3541,6 +3560,87 @@ class CEnumType(CType):
' %s'
%
code
.
error_goto_if
(
error_condition
or
self
.
error_condition
(
result_code
),
error_pos
))
class
CTupleType
(
CType
):
# components [PyrexType]
is_ctuple
=
True
def
__init__
(
self
,
cname
,
components
):
self
.
cname
=
cname
self
.
components
=
components
self
.
size
=
len
(
components
)
self
.
to_py_function
=
"%s_to_py_%s"
%
(
Naming
.
convert_func_prefix
,
self
.
cname
)
self
.
from_py_function
=
"%s_from_py_%s"
%
(
Naming
.
convert_func_prefix
,
self
.
cname
)
self
.
exception_check
=
True
self
.
_convert_to_py_code
=
None
self
.
_convert_from_py_code
=
None
def
__str__
(
self
):
return
"(%s)"
%
", "
.
join
(
str
(
c
)
for
c
in
self
.
components
)
def
declaration_code
(
self
,
entity_code
,
for_display
=
0
,
dll_linkage
=
None
,
pyrex
=
0
):
if
pyrex
or
for_display
:
return
str
(
self
)
else
:
return
self
.
base_declaration_code
(
self
.
cname
,
entity_code
)
def
create_to_py_utility_code
(
self
,
env
):
if
self
.
_convert_to_py_code
is
False
:
return
None
# tri-state-ish
if
self
.
_convert_to_py_code
is
None
:
for
component
in
self
.
components
:
if
not
component
.
create_to_py_utility_code
(
env
):
self
.
to_py_function
=
None
self
.
_convert_to_py_code
=
False
return
False
context
=
dict
(
struct_type_decl
=
self
.
empty_declaration_code
(),
components
=
self
.
components
,
funcname
=
self
.
to_py_function
,
size
=
len
(
self
.
components
)
)
self
.
_convert_to_py_code
=
TempitaUtilityCode
.
load
(
"ToPyCTupleUtility"
,
"TypeConversion.c"
,
context
=
context
)
env
.
use_utility_code
(
self
.
_convert_to_py_code
)
return
True
def
create_from_py_utility_code
(
self
,
env
):
if
self
.
_convert_from_py_code
is
False
:
return
None
# tri-state-ish
if
self
.
_convert_from_py_code
is
None
:
for
component
in
self
.
components
:
if
not
component
.
create_from_py_utility_code
(
env
):
self
.
from_py_function
=
None
self
.
_convert_from_py_code
=
False
return
False
context
=
dict
(
struct_type_decl
=
self
.
empty_declaration_code
(),
components
=
self
.
components
,
funcname
=
self
.
from_py_function
,
size
=
len
(
self
.
components
)
)
self
.
_convert_from_py_code
=
TempitaUtilityCode
.
load
(
"FromPyCTupleUtility"
,
"TypeConversion.c"
,
context
=
context
)
env
.
use_utility_code
(
self
.
_convert_from_py_code
)
return
True
c_tuple_types
=
{}
def
c_tuple_type
(
components
):
components
=
tuple
(
components
)
tuple_type
=
c_tuple_types
.
get
(
components
)
if
tuple_type
is
None
:
cname
=
'__pyx_tuple_'
+
type_list_identifier
(
components
)
tuple_type
=
c_tuple_types
[
components
]
=
CTupleType
(
cname
,
components
)
return
tuple_type
class
UnspecifiedType
(
PyrexType
):
# Used as a placeholder until the type can be determined.
...
...
@@ -3819,7 +3919,7 @@ def best_match(args, functions, pos=None, env=None):
from
.Symtab
import
Entry
specialization
=
Entry
(
name
=
func
.
name
+
"[%s]"
%
","
.
join
([
str
(
t
)
for
t
in
type_list
]),
cname
=
func
.
cname
+
"<%s>"
%
","
.
join
([
t
.
declaration_code
(
""
)
for
t
in
type_list
]),
cname
=
func
.
cname
+
"<%s>"
%
","
.
join
([
t
.
empty_declaration_code
(
)
for
t
in
type_list
]),
type
=
func_type
.
specialize
(
deductions
),
pos
=
func
.
pos
)
candidates
.
append
((
specialization
,
specialization
.
type
))
...
...
@@ -4138,3 +4238,37 @@ def typecast(to_type, from_type, expr_code):
else
:
#print "typecast: to", to_type, "from", from_type ###
return
to_type
.
cast_code
(
expr_code
)
def
type_list_identifier
(
types
):
return
cap_length
(
'__and_'
.
join
(
type_identifier
(
type
)
for
type
in
types
))
_type_identifier_cache
=
{}
def
type_identifier
(
type
):
decl
=
type
.
empty_declaration_code
()
safe
=
_type_identifier_cache
.
get
(
decl
)
if
safe
is
None
:
safe
=
decl
safe
=
re
.
sub
(
' +'
,
' '
,
safe
)
safe
=
re
.
sub
(
' ([^a-zA-Z0-9_])'
,
r'\1'
,
safe
)
safe
=
re
.
sub
(
'([^a-zA-Z0-9_]) '
,
r'\1'
,
safe
)
safe
=
(
safe
.
replace
(
'__'
,
'__dunder'
)
.
replace
(
' '
,
'__space_'
)
.
replace
(
'*'
,
'__ptr'
)
.
replace
(
'&'
,
'__ref'
)
.
replace
(
'['
,
'__lArr'
)
.
replace
(
']'
,
'__rArr'
)
.
replace
(
'<'
,
'__lAng'
)
.
replace
(
'>'
,
'__rAng'
)
.
replace
(
'('
,
'__lParen'
)
.
replace
(
')'
,
'__rParen'
)
.
replace
(
','
,
'__comma_'
)
.
replace
(
'::'
,
'__in_'
))
safe
=
cap_length
(
re
.
sub
(
'[^a-zA-Z0-9_]'
,
lambda
x
:
'__%X'
%
ord
(
x
.
group
(
0
)),
safe
))
_type_identifier_cache
[
decl
]
=
safe
return
safe
def
cap_length
(
s
,
max_prefix
=
63
,
max_len
=
1024
):
if
len
(
s
)
<=
max_prefix
:
return
s
else
:
return
'%x__%s__etc'
%
(
abs
(
hash
(
s
))
%
(
1
<<
20
),
s
[:
max_len
-
17
])
Cython/Compiler/Symtab.py
View file @
0527db06
...
...
@@ -606,6 +606,9 @@ class Scope(object):
self
.
sue_entries
.
append
(
entry
)
return
entry
def
declare_tuple_type
(
self
,
pos
,
type
):
return
self
.
outer_scope
.
declare_tuple_type
(
pos
,
type
)
def
declare_var
(
self
,
name
,
type
,
pos
,
cname
=
None
,
visibility
=
'private'
,
api
=
0
,
in_pxd
=
0
,
is_cdef
=
0
):
...
...
@@ -1061,6 +1064,18 @@ class ModuleScope(Scope):
return
self
.
outer_scope
.
lookup
(
name
,
language_level
=
language_level
)
def
declare_tuple_type
(
self
,
pos
,
type
):
cname
=
type
.
cname
if
not
self
.
lookup_here
(
cname
):
scope
=
StructOrUnionScope
(
cname
)
for
ix
,
component
in
enumerate
(
type
.
components
):
scope
.
declare_var
(
name
=
"f%s"
%
ix
,
type
=
component
,
pos
=
pos
)
struct_entry
=
self
.
declare_struct_or_union
(
cname
+
'_struct'
,
'struct'
,
scope
,
typedef_flag
=
True
,
pos
=
pos
,
cname
=
cname
)
self
.
type_entries
.
remove
(
struct_entry
)
type
.
struct_entry
=
struct_entry
type
.
entry
=
self
.
declare_type
(
cname
,
type
,
pos
,
cname
)
return
type
.
entry
def
declare_builtin
(
self
,
name
,
pos
):
if
not
hasattr
(
builtins
,
name
)
\
and
name
not
in
Code
.
non_portable_builtins_map
\
...
...
@@ -2114,8 +2129,8 @@ class CppClassScope(Scope):
entry
=
self
.
declare
(
name
,
cname
,
type
,
pos
,
visibility
)
entry
.
is_variable
=
1
if
type
.
is_cfunction
and
self
.
type
:
if
not
self
.
type
.
templates
or
not
any
(
T
.
is_fused
for
T
in
self
.
type
.
templates
)
:
entry
.
func_cname
=
"%s::%s"
%
(
self
.
type
.
declaration_code
(
""
),
cname
)
if
not
self
.
type
.
get_fused_types
:
entry
.
func_cname
=
"%s::%s"
%
(
self
.
type
.
empty_declaration_code
(
),
cname
)
if
name
!=
"this"
and
(
defining
or
name
!=
"<init>"
):
self
.
var_entries
.
append
(
entry
)
if
type
.
is_pyobject
and
not
allow_pyobject
:
...
...
Cython/Utility/TypeConversion.c
View file @
0527db06
...
...
@@ -311,6 +311,55 @@ static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
}
/////////////// ToPyCTupleUtility.proto ///////////////
static
PyObject
*
{{
funcname
}}({{
struct_type_decl
}});
/////////////// ToPyCTupleUtility ///////////////
static
PyObject
*
{{
funcname
}}({{
struct_type_decl
}}
value
)
{
PyObject
*
item
=
NULL
;
PyObject
*
result
=
PyTuple_New
({{
size
}});
if
(
!
result
)
goto
bad
;
{{
for
ix
,
component
in
enumerate
(
components
)
:
}}
{{
py
:
attr
=
"value.f%s"
%
ix
}}
item
=
{{
component
.
to_py_function
}}({{
attr
}});
if
(
!
item
)
goto
bad
;
PyTuple_SET_ITEM
(
result
,
{{
ix
}},
item
);
{{
endfor
}}
return
result
;
bad:
Py_XDECREF
(
item
);
Py_XDECREF
(
result
);
return
NULL
;
}
/////////////// FromPyCTupleUtility.proto ///////////////
static
{{
struct_type_decl
}}
{{
funcname
}}(
PyObject
*
);
/////////////// FromPyCTupleUtility ///////////////
static
{{
struct_type_decl
}}
{{
funcname
}}(
PyObject
*
o
)
{
{{
struct_type_decl
}}
result
;
if
(
!
PyTuple_Check
(
o
)
||
PyTuple_GET_SIZE
(
o
)
!=
{{
size
}})
{
PyErr_Format
(
PyExc_TypeError
,
"Expected %.16s of size %.8d, got %.200s"
,
"a tuple"
,
{{
size
}},
Py_TYPE
(
o
)
->
tp_name
);
goto
bad
;
}
{{
for
ix
,
component
in
enumerate
(
components
)
:
}}
{{
py
:
attr
=
"result.f%s"
%
ix
}}
{{
attr
}}
=
{{
component
.
from_py_function
}}(
PyTuple_GET_ITEM
(
o
,
{{
ix
}}));
if
({{
component
.
error_condition
(
attr
)}})
goto
bad
;
{{
endfor
}}
return
result
;
bad:
return
result
;
}
/////////////// ObjectAsUCS4.proto ///////////////
static
CYTHON_INLINE
Py_UCS4
__Pyx_PyObject_AsPy_UCS4
(
PyObject
*
);
...
...
tests/run/arrayassign.pyx
View file @
0527db06
...
...
@@ -141,6 +141,24 @@ def test_ptr_literal_list_slice_end():
a
[:
5
]
=
[
1
,
2
,
3
,
4
,
5
]
return
(
a
[
0
],
a
[
1
],
a
[
2
],
a
[
3
],
a
[
4
])
def
test_multiple_from_slice
():
"""
>>> test_multiple_from_slice()
(5, 4, 3)
"""
cdef
int
*
a
=
[
6
,
5
,
4
,
3
,
2
,
1
]
x
,
y
,
z
=
a
[
1
:
4
]
return
x
,
y
,
z
def
test_slice_from_multiple
():
"""
>>> test_slice_from_multiple()
(6, -1, -2, -3, 2, 1)
"""
cdef
int
*
a
=
[
6
,
5
,
4
,
3
,
2
,
1
]
a
[
1
:
4
]
=
-
1
,
-
2
,
-
3
return
a
[
0
],
a
[
1
],
a
[
2
],
a
[
3
],
a
[
4
],
a
[
5
]
def
test_literal_tuple
():
"""
>>> test_literal_tuple()
...
...
tests/run/ctuple.pyx
0 → 100644
View file @
0527db06
import
cython
def
simple_convert
(
*
o
):
"""
>>> simple_convert(1, 2)
(1, 2.0)
>>> simple_convert(1)
Traceback (most recent call last):
...
TypeError: Expected a tuple of size 2, got tuple
>>> simple_convert(1, 2, 3)
Traceback (most recent call last):
...
TypeError: Expected a tuple of size 2, got tuple
"""
cdef
(
int
,
double
)
xy
=
o
return
xy
def
indexing
((
int
,
double
)
xy
):
"""
>>> indexing((1, 2))
(2, 3.0)
"""
x
=
xy
[
0
]
y
=
xy
[
1
]
xy
[
0
]
=
x
+
1
xy
[
1
]
=
y
+
1
return
xy
def
unpacking
((
int
,
double
)
xy
):
"""
>>> unpacking((1, 2))
(1, 2.0)
"""
x
,
y
=
xy
return
x
,
y
cdef
(
int
,
double
)
side_effect
((
int
,
double
)
xy
):
print
"called with"
,
xy
return
xy
def
unpacking_with_side_effect
((
int
,
double
)
xy
):
"""
>>> unpacking_with_side_effect((1, 2))
called with (1, 2.0)
(1, 2.0)
"""
x
,
y
=
side_effect
(
xy
)
return
x
,
y
def
packing_tuple
(
int
x
,
double
y
):
"""
>>> packing_tuple(1, 2)
(1, 2.0)
"""
cdef
(
int
,
double
)
xy
=
(
x
,
y
)
return
xy
def
coerce_packing_tuple
(
int
x
,
int
y
):
cdef
(
int
,
double
)
xy
=
(
x
,
y
)
"""
>>> coerce_packing_tuple(1, 2)
(1, 2.0)
"""
return
xy
def
c_types
(
int
a
,
double
b
):
"""
>>> c_types(1, 2)
(1, 2.0)
"""
cdef
int
*
a_ptr
cdef
double
*
b_ptr
cdef
(
int
*
,
double
*
)
ab
=
(
&
a
,
&
b
)
a_ptr
,
b_ptr
=
ab
return
a_ptr
[
0
],
b_ptr
[
0
]
cdef
(
int
,
int
*
)
cdef
_ctuple_return_type
(
int
x
,
int
*
x_ptr
):
return
x
,
x_ptr
def
call_cdef_ctuple_return_type
(
int
x
):
"""
>>> call_cdef_ctuple_return_type(2)
(2, 2)
"""
cdef
(
int
,
int
*
)
res
=
cdef
_ctuple_return_type
(
x
,
&
x
)
return
res
[
0
],
res
[
1
][
0
]
cpdef
(
int
,
double
)
cpdef
_ctuple_return_type
(
int
x
,
double
y
):
"""
>>> cpdef_ctuple_return_type(1, 2)
(1, 2.0)
"""
return
x
,
y
@
cython
.
infer_types
(
True
)
def
test_type_inference
():
"""
>>> test_type_inference()
"""
cdef
int
x
=
1
cdef
double
y
=
2
cdef
object
o
=
3
xy
=
(
x
,
y
)
assert
cython
.
typeof
(
xy
)
==
"(int, double)"
,
cython
.
typeof
(
xy
)
xo
=
(
x
,
o
)
assert
cython
.
typeof
(
xo
)
==
"tuple object"
,
cython
.
typeof
(
xo
)
def
test_equality
((
int
,
int
)
ab
,
(
int
,
int
)
cd
,
(
int
,
int
)
ef
):
"""
>>> test_equality((1, 2), (3, 4), (5, 6))
True
>>> test_equality((1, 2), (3, 4), (3, 4))
True
>>> test_equality((3, 4), (3, 4), (3, 4))
False
"""
return
ab
<
cd
<=
ef
def
test_binop
((
int
,
int
)
ab
,
(
double
,
double
)
cd
):
"""
>>> test_binop((1, 2), (3, 4))
(1, 2, 3.0, 4.0)
"""
return
ab
+
cd
def
test_mul
((
int
,
int
)
ab
,
int
c
):
"""
>>> test_mul((1, 2), 3)
(1, 2, 1, 2, 1, 2)
"""
return
ab
*
c
def
test_unop
((
int
,
int
)
ab
):
"""
>>> test_unop((1, 2))
True
"""
return
not
ab
tests/run/type_inference.pyx
View file @
0527db06
...
...
@@ -32,8 +32,10 @@ def simple():
assert
typeof
(
u
)
==
"unicode object"
,
typeof
(
u
)
L
=
[
1
,
2
,
3
]
assert
typeof
(
L
)
==
"list object"
,
typeof
(
L
)
t
=
(
4
,
5
,
6
)
t
=
(
4
,
5
,
6
,()
)
assert
typeof
(
t
)
==
"tuple object"
,
typeof
(
t
)
t2
=
(
4
,
5.0
,
6
)
assert
typeof
(
t2
)
==
"(long, double, long)"
,
typeof
(
t
)
def
builtin_types
():
"""
...
...
@@ -80,7 +82,7 @@ def slicing():
assert
typeof
(
L1
)
==
"list object"
,
typeof
(
L1
)
L2
=
L
[
1
:
2
:
2
]
assert
typeof
(
L2
)
==
"list object"
,
typeof
(
L2
)
t
=
(
4
,
5
,
6
)
t
=
(
4
,
5
,
6
,()
)
assert
typeof
(
t
)
==
"tuple object"
,
typeof
(
t
)
t1
=
t
[
1
:
2
]
assert
typeof
(
t1
)
==
"tuple object"
,
typeof
(
t1
)
...
...
@@ -107,7 +109,7 @@ def indexing():
assert
typeof
(
L
)
==
"list object"
,
typeof
(
L
)
L1
=
L
[
1
]
assert
typeof
(
L1
)
==
"Python object"
,
typeof
(
L1
)
t
=
(
4
,
5
,
6
)
t
=
(
4
,
5
,
()
)
assert
typeof
(
t
)
==
"tuple object"
,
typeof
(
t
)
t1
=
t
[
1
]
assert
typeof
(
t1
)
==
"long"
,
typeof
(
t1
)
...
...
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