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
406674e1
Commit
406674e1
authored
Apr 21, 2010
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
generic way to wrap an ExprNode in a NoneCheckNode
parent
d1b5807f
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
89 additions
and
25 deletions
+89
-25
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+76
-8
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+13
-17
No files found.
Cython/Compiler/ExprNodes.py
View file @
406674e1
...
@@ -636,10 +636,22 @@ class ExprNode(Node):
...
@@ -636,10 +636,22 @@ class ExprNode(Node):
# a constant, local var, C global var, struct member
# a constant, local var, C global var, struct member
# reference, or temporary.
# reference, or temporary.
return
self
.
result_in_temp
()
return
self
.
result_in_temp
()
def
may_be_none
(
self
):
return
self
.
type
.
is_pyobject
def
as_cython_attribute
(
self
):
def
as_cython_attribute
(
self
):
return
None
return
None
def
as_none_safe_node
(
self
,
error
,
message
):
# Wraps the node in a NoneCheckNode if it is not known to be
# not-None (e.g. because it is a Python literal).
if
self
.
may_be_none
():
return
NoneCheckNode
(
self
,
error
,
message
)
else
:
return
self
class
AtomicExprNode
(
ExprNode
):
class
AtomicExprNode
(
ExprNode
):
# Abstract base class for expression nodes which have
# Abstract base class for expression nodes which have
# no sub-expressions.
# no sub-expressions.
...
@@ -660,7 +672,10 @@ class PyConstNode(AtomicExprNode):
...
@@ -660,7 +672,10 @@ class PyConstNode(AtomicExprNode):
def
is_simple
(
self
):
def
is_simple
(
self
):
return
1
return
1
def
may_be_none
(
self
):
return
False
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
pass
pass
...
@@ -682,7 +697,11 @@ class NoneNode(PyConstNode):
...
@@ -682,7 +697,11 @@ class NoneNode(PyConstNode):
def
compile_time_value
(
self
,
denv
):
def
compile_time_value
(
self
,
denv
):
return
None
return
None
def
may_be_none
(
self
):
return
True
class
EllipsisNode
(
PyConstNode
):
class
EllipsisNode
(
PyConstNode
):
# '...' in a subscript list.
# '...' in a subscript list.
...
@@ -704,7 +723,10 @@ class ConstNode(AtomicExprNode):
...
@@ -704,7 +723,10 @@ class ConstNode(AtomicExprNode):
def
is_simple
(
self
):
def
is_simple
(
self
):
return
1
return
1
def
may_be_none
(
self
):
return
False
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
pass
# Types are held in class variables
pass
# Types are held in class variables
...
@@ -1012,6 +1034,9 @@ class LongNode(AtomicExprNode):
...
@@ -1012,6 +1034,9 @@ class LongNode(AtomicExprNode):
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
self
.
is_temp
=
1
self
.
is_temp
=
1
def
may_be_none
(
self
):
return
False
gil_message
=
"Constructing Python long int"
gil_message
=
"Constructing Python long int"
def
generate_result_code
(
self
,
code
):
def
generate_result_code
(
self
,
code
):
...
@@ -1039,6 +1064,9 @@ class ImagNode(AtomicExprNode):
...
@@ -1039,6 +1064,9 @@ class ImagNode(AtomicExprNode):
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
self
.
type
.
create_declaration_utility_code
(
env
)
self
.
type
.
create_declaration_utility_code
(
env
)
def
may_be_none
(
self
):
return
False
def
coerce_to
(
self
,
dst_type
,
env
):
def
coerce_to
(
self
,
dst_type
,
env
):
if
self
.
type
is
dst_type
:
if
self
.
type
is
dst_type
:
return
self
return
self
...
@@ -1098,7 +1126,10 @@ class NewExprNode(AtomicExprNode):
...
@@ -1098,7 +1126,10 @@ class NewExprNode(AtomicExprNode):
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
if
self
.
type
is
None
:
if
self
.
type
is
None
:
self
.
infer_type
(
env
)
self
.
infer_type
(
env
)
def
may_be_none
(
self
):
return
False
def
generate_result_code
(
self
,
code
):
def
generate_result_code
(
self
,
code
):
pass
pass
...
@@ -2958,6 +2989,9 @@ class AsTupleNode(ExprNode):
...
@@ -2958,6 +2989,9 @@ class AsTupleNode(ExprNode):
self
.
type
=
tuple_type
self
.
type
=
tuple_type
self
.
is_temp
=
1
self
.
is_temp
=
1
def
may_be_none
(
self
):
return
False
nogil_check
=
Node
.
gil_error
nogil_check
=
Node
.
gil_error
gil_message
=
"Constructing Python tuple"
gil_message
=
"Constructing Python tuple"
...
@@ -3434,6 +3468,9 @@ class SequenceNode(ExprNode):
...
@@ -3434,6 +3468,9 @@ class SequenceNode(ExprNode):
self
.
type
=
py_object_type
self
.
type
=
py_object_type
self
.
is_temp
=
1
self
.
is_temp
=
1
def
may_be_none
(
self
):
return
False
def
analyse_target_types
(
self
,
env
):
def
analyse_target_types
(
self
,
env
):
self
.
iterator
=
PyTempNode
(
self
.
pos
,
env
)
self
.
iterator
=
PyTempNode
(
self
.
pos
,
env
)
self
.
unpacked_items
=
[]
self
.
unpacked_items
=
[]
...
@@ -3817,6 +3854,9 @@ class ComprehensionNode(ExprNode):
...
@@ -3817,6 +3854,9 @@ class ComprehensionNode(ExprNode):
self
.
type
=
self
.
target
.
type
self
.
type
=
self
.
target
.
type
self
.
loop
.
analyse_expressions
(
env
)
self
.
loop
.
analyse_expressions
(
env
)
def
may_be_none
(
self
):
return
False
def
calculate_result_code
(
self
):
def
calculate_result_code
(
self
):
return
self
.
target
.
result
()
return
self
.
target
.
result
()
...
@@ -3897,6 +3937,9 @@ class SetNode(ExprNode):
...
@@ -3897,6 +3937,9 @@ class SetNode(ExprNode):
self
.
type
=
set_type
self
.
type
=
set_type
self
.
is_temp
=
1
self
.
is_temp
=
1
def
may_be_none
(
self
):
return
False
def
calculate_constant_result
(
self
):
def
calculate_constant_result
(
self
):
self
.
constant_result
=
set
([
self
.
constant_result
=
set
([
arg
.
constant_result
for
arg
in
self
.
args
])
arg
.
constant_result
for
arg
in
self
.
args
])
...
@@ -3964,6 +4007,9 @@ class DictNode(ExprNode):
...
@@ -3964,6 +4007,9 @@ class DictNode(ExprNode):
item
.
analyse_types
(
env
)
item
.
analyse_types
(
env
)
self
.
obj_conversion_errors
=
held_errors
()
self
.
obj_conversion_errors
=
held_errors
()
release_errors
(
ignore
=
True
)
release_errors
(
ignore
=
True
)
def
may_be_none
(
self
):
return
False
def
coerce_to
(
self
,
dst_type
,
env
):
def
coerce_to
(
self
,
dst_type
,
env
):
if
dst_type
.
is_pyobject
:
if
dst_type
.
is_pyobject
:
...
@@ -4094,6 +4140,9 @@ class ClassNode(ExprNode):
...
@@ -4094,6 +4140,9 @@ class ClassNode(ExprNode):
self
.
is_temp
=
1
self
.
is_temp
=
1
env
.
use_utility_code
(
create_class_utility_code
);
env
.
use_utility_code
(
create_class_utility_code
);
def
may_be_none
(
self
):
return
False
gil_message
=
"Constructing Python class"
gil_message
=
"Constructing Python class"
def
generate_result_code
(
self
,
code
):
def
generate_result_code
(
self
,
code
):
...
@@ -4129,6 +4178,9 @@ class UnboundMethodNode(ExprNode):
...
@@ -4129,6 +4178,9 @@ class UnboundMethodNode(ExprNode):
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
self
.
function
.
analyse_types
(
env
)
self
.
function
.
analyse_types
(
env
)
def
may_be_none
(
self
):
return
False
gil_message
=
"Constructing an unbound method"
gil_message
=
"Constructing an unbound method"
def
generate_result_code
(
self
,
code
):
def
generate_result_code
(
self
,
code
):
...
@@ -4154,6 +4206,9 @@ class PyCFunctionNode(AtomicExprNode):
...
@@ -4154,6 +4206,9 @@ class PyCFunctionNode(AtomicExprNode):
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
pass
pass
def
may_be_none
(
self
):
return
False
gil_message
=
"Constructing Python function"
gil_message
=
"Constructing Python function"
...
@@ -4675,7 +4730,10 @@ class TypeofNode(ExprNode):
...
@@ -4675,7 +4730,10 @@ class TypeofNode(ExprNode):
self
.
pos
,
value
=
StringEncoding
.
EncodedString
(
str
(
self
.
operand
.
type
)))
self
.
pos
,
value
=
StringEncoding
.
EncodedString
(
str
(
self
.
operand
.
type
)))
self
.
literal
.
analyse_types
(
env
)
self
.
literal
.
analyse_types
(
env
)
self
.
literal
=
self
.
literal
.
coerce_to_pyobject
(
env
)
self
.
literal
=
self
.
literal
.
coerce_to_pyobject
(
env
)
def
may_be_none
(
self
):
return
False
def
generate_evaluation_code
(
self
,
code
):
def
generate_evaluation_code
(
self
,
code
):
self
.
literal
.
generate_evaluation_code
(
code
)
self
.
literal
.
generate_evaluation_code
(
code
)
...
@@ -5756,8 +5814,8 @@ class PrimaryCmpNode(ExprNode, CmpNode):
...
@@ -5756,8 +5814,8 @@ class PrimaryCmpNode(ExprNode, CmpNode):
self
.
operand2
=
self
.
operand2
.
coerce_to
(
bytes_type
,
env
)
self
.
operand2
=
self
.
operand2
.
coerce_to
(
bytes_type
,
env
)
env
.
use_utility_code
(
char_in_bytes_utility_code
)
env
.
use_utility_code
(
char_in_bytes_utility_code
)
if
not
isinstance
(
self
.
operand2
,
(
UnicodeNode
,
BytesNode
)):
if
not
isinstance
(
self
.
operand2
,
(
UnicodeNode
,
BytesNode
)):
self
.
operand2
=
NoneCheckN
ode
(
self
.
operand2
=
self
.
operand2
.
as_none_safe_n
ode
(
self
.
operand2
,
"PyExc_TypeError"
,
"PyExc_TypeError"
,
"argument of type 'NoneType' is not iterable"
)
"argument of type 'NoneType' is not iterable"
)
else
:
else
:
common_type
=
py_object_type
common_type
=
py_object_type
...
@@ -6087,6 +6145,9 @@ class NoneCheckNode(CoercionNode):
...
@@ -6087,6 +6145,9 @@ class NoneCheckNode(CoercionNode):
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
pass
pass
def
may_be_none
(
self
):
return
False
def
result_in_temp
(
self
):
def
result_in_temp
(
self
):
return
self
.
arg
.
result_in_temp
()
return
self
.
arg
.
result_in_temp
()
...
@@ -6129,6 +6190,10 @@ class CoerceToPyTypeNode(CoercionNode):
...
@@ -6129,6 +6190,10 @@ class CoerceToPyTypeNode(CoercionNode):
gil_message
=
"Converting to Python object"
gil_message
=
"Converting to Python object"
def
may_be_none
(
self
):
# FIXME: is this always safe?
return
False
def
coerce_to_boolean
(
self
,
env
):
def
coerce_to_boolean
(
self
,
env
):
return
self
.
arg
.
coerce_to_boolean
(
env
).
coerce_to_temp
(
env
)
return
self
.
arg
.
coerce_to_boolean
(
env
).
coerce_to_temp
(
env
)
...
@@ -6351,6 +6416,9 @@ class ModuleRefNode(ExprNode):
...
@@ -6351,6 +6416,9 @@ class ModuleRefNode(ExprNode):
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
pass
pass
def
may_be_none
(
self
):
return
False
def
calculate_result_code
(
self
):
def
calculate_result_code
(
self
):
return
Naming
.
module_cname
return
Naming
.
module_cname
...
...
Cython/Compiler/Optimize.py
View file @
406674e1
...
@@ -173,8 +173,7 @@ class IterationTransform(Visitor.VisitorTransform):
...
@@ -173,8 +173,7 @@ class IterationTransform(Visitor.VisitorTransform):
return
node
return
node
unpack_temp_node
=
UtilNodes
.
LetRefNode
(
unpack_temp_node
=
UtilNodes
.
LetRefNode
(
ExprNodes
.
NoneCheckNode
(
slice_node
.
as_none_safe_node
(
"PyExc_TypeError"
,
"'NoneType' is not iterable"
))
slice_node
,
"PyExc_TypeError"
,
"'NoneType' is not iterable"
))
slice_base_node
=
ExprNodes
.
PythonCapiCallNode
(
slice_base_node
=
ExprNodes
.
PythonCapiCallNode
(
slice_node
.
pos
,
unpack_func
,
unpack_func_type
,
slice_node
.
pos
,
unpack_func
,
unpack_func_type
,
...
@@ -1313,8 +1312,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1313,8 +1312,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
node
return
node
arg
=
pos_args
[
0
]
arg
=
pos_args
[
0
]
if
arg
.
type
is
Builtin
.
dict_type
:
if
arg
.
type
is
Builtin
.
dict_type
:
arg
=
ExprNodes
.
NoneCheckNode
(
arg
=
arg
.
as_none_safe_node
(
"PyExc_TypeError"
,
"'NoneType' is not iterable"
)
arg
,
"PyExc_TypeError"
,
"'NoneType' is not iterable"
)
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"PyDict_Copy"
,
self
.
PyDict_Copy_func_type
,
node
.
pos
,
"PyDict_Copy"
,
self
.
PyDict_Copy_func_type
,
args
=
[
arg
],
args
=
[
arg
],
...
@@ -1337,9 +1335,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1337,9 +1335,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
node
return
node
if
not
isinstance
(
list_arg
,
(
ExprNodes
.
ComprehensionNode
,
if
not
isinstance
(
list_arg
,
(
ExprNodes
.
ComprehensionNode
,
ExprNodes
.
ListNode
)):
ExprNodes
.
ListNode
)):
pos_args
[
0
]
=
ExprNodes
.
NoneCheckNode
(
pos_args
[
0
]
=
list_arg
.
as_none_safe_node
(
list_arg
,
"PyExc_TypeError"
,
"PyExc_TypeError"
,
"'NoneType' object is not iterable"
)
"'NoneType' object is not iterable"
)
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"PyList_AsTuple"
,
self
.
PyList_AsTuple_func_type
,
node
.
pos
,
"PyList_AsTuple"
,
self
.
PyList_AsTuple_func_type
,
...
@@ -1499,9 +1496,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1499,9 +1496,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
if
cfunc_name
is
None
:
if
cfunc_name
is
None
:
return
node
return
node
if
not
arg
.
is_literal
:
if
not
arg
.
is_literal
:
arg
=
ExprNodes
.
NoneCheckNode
(
arg
=
arg
.
as_none_safe_node
(
arg
,
"PyExc_TypeError"
,
"PyExc_TypeError"
,
"object of type 'NoneType' has no len()"
)
"object of type 'NoneType' has no len()"
)
new_node
=
ExprNodes
.
PythonCapiCallNode
(
new_node
=
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
cfunc_name
,
self
.
PyObject_Size_func_type
,
node
.
pos
,
cfunc_name
,
self
.
PyObject_Size_func_type
,
args
=
[
arg
],
args
=
[
arg
],
...
@@ -1564,8 +1560,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1564,8 +1560,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
if
not
type_arg
.
type_entry
:
if
not
type_arg
.
type_entry
:
# arbitrary variable, needs a None check for safety
# arbitrary variable, needs a None check for safety
type_arg
=
ExprNodes
.
NoneCheckN
ode
(
type_arg
=
type_arg
.
as_none_safe_n
ode
(
type_arg
,
"PyExc_TypeError"
,
"PyExc_TypeError"
,
"object.__new__(X): X is not a type object (NoneType)"
)
"object.__new__(X): X is not a type object (NoneType)"
)
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
...
@@ -2126,13 +2122,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -2126,13 +2122,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
if
args
and
not
args
[
0
].
is_literal
:
if
args
and
not
args
[
0
].
is_literal
:
self_arg
=
args
[
0
]
self_arg
=
args
[
0
]
if
is_unbound_method
:
if
is_unbound_method
:
self_arg
=
ExprNodes
.
NoneCheckN
ode
(
self_arg
=
self_arg
.
as_none_safe_n
ode
(
self_arg
,
"PyExc_TypeError"
,
"PyExc_TypeError"
,
"descriptor '%s' requires a '%s' object but received a 'NoneType'"
%
(
"descriptor '%s' requires a '%s' object but received a 'NoneType'"
%
(
attr_name
,
node
.
function
.
obj
.
name
))
attr_name
,
node
.
function
.
obj
.
name
))
else
:
else
:
self_arg
=
ExprNodes
.
NoneCheckN
ode
(
self_arg
=
self_arg
.
as_none_safe_n
ode
(
self_arg
,
"PyExc_AttributeError"
,
"PyExc_AttributeError"
,
"'NoneType' object has no attribute '%s'"
%
attr_name
)
"'NoneType' object has no attribute '%s'"
%
attr_name
)
args
[
0
]
=
self_arg
args
[
0
]
=
self_arg
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
...
...
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