Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cython
Commits
7bf952b2
Commit
7bf952b2
authored
May 30, 2008
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
f1d9c4af
8b2a1153
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
445 additions
and
111 deletions
+445
-111
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+125
-81
Cython/Compiler/Lexicon.py
Cython/Compiler/Lexicon.py
+3
-1
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+156
-0
Cython/Compiler/Naming.py
Cython/Compiler/Naming.py
+2
-0
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+54
-12
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+24
-16
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+6
-1
tests/compile/forfromelse.pyx
tests/compile/forfromelse.pyx
+5
-0
tests/compile/indices.pyx
tests/compile/indices.pyx
+17
-0
tests/run/big_indices.pyx
tests/run/big_indices.pyx
+25
-0
tests/run/inplace.pyx
tests/run/inplace.pyx
+28
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
7bf952b2
...
@@ -180,7 +180,7 @@ class ExprNode(Node):
...
@@ -180,7 +180,7 @@ class ExprNode(Node):
print_call_chain
(
method_name
,
"not implemented"
)
###
print_call_chain
(
method_name
,
"not implemented"
)
###
raise
InternalError
(
raise
InternalError
(
"%s.%s not implemented"
%
"%s.%s not implemented"
%
(
self
.
__class__
.
__name__
,
method_name
))
(
self
.
__class__
.
__name__
,
method_name
))
def
is_lvalue
(
self
):
def
is_lvalue
(
self
):
return
0
return
0
...
@@ -963,7 +963,7 @@ class NameNode(AtomicExprNode):
...
@@ -963,7 +963,7 @@ class NameNode(AtomicExprNode):
self
.
result_code
,
self
.
result_code
,
namespace
,
namespace
,
self
.
interned_cname
,
self
.
interned_cname
,
code
.
error_goto_if_null
(
self
.
result_code
,
self
.
pos
)))
code
.
error_goto_if_null
(
self
.
result_code
,
self
.
pos
)))
elif
entry
.
is_local
and
False
:
elif
entry
.
is_local
and
False
:
# control flow not good enough yet
# control flow not good enough yet
assigned
=
entry
.
scope
.
control_flow
.
get_state
((
entry
.
name
,
'initalized'
),
self
.
pos
)
assigned
=
entry
.
scope
.
control_flow
.
get_state
((
entry
.
name
,
'initalized'
),
self
.
pos
)
...
@@ -1226,7 +1226,7 @@ class IndexNode(ExprNode):
...
@@ -1226,7 +1226,7 @@ class IndexNode(ExprNode):
# base ExprNode
# base ExprNode
# index ExprNode
# index ExprNode
subexprs
=
[
'base'
,
'index'
,
'py_index'
]
subexprs
=
[
'base'
,
'index'
]
def
compile_time_value
(
self
,
denv
):
def
compile_time_value
(
self
,
denv
):
base
=
self
.
base
.
compile_time_value
(
denv
)
base
=
self
.
base
.
compile_time_value
(
denv
)
...
@@ -1243,19 +1243,27 @@ class IndexNode(ExprNode):
...
@@ -1243,19 +1243,27 @@ class IndexNode(ExprNode):
pass
pass
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
self
.
analyse_base_and_index_types
(
env
,
getting
=
1
)
def
analyse_target_types
(
self
,
env
):
self
.
analyse_base_and_index_types
(
env
,
setting
=
1
)
def
analyse_base_and_index_types
(
self
,
env
,
getting
=
0
,
setting
=
0
):
self
.
base
.
analyse_types
(
env
)
self
.
base
.
analyse_types
(
env
)
self
.
index
.
analyse_types
(
env
)
self
.
index
.
analyse_types
(
env
)
if
self
.
base
.
type
.
is_pyobject
:
if
self
.
base
.
type
.
is_pyobject
:
if
self
.
index
.
type
.
is_int
:
if
self
.
index
.
type
.
is_int
:
self
.
original_index_type
=
self
.
index
.
type
self
.
index
=
self
.
index
.
coerce_to
(
PyrexTypes
.
c_py_ssize_t_type
,
env
).
coerce_to_simple
(
env
)
self
.
index
=
self
.
index
.
coerce_to
(
PyrexTypes
.
c_py_ssize_t_type
,
env
).
coerce_to_simple
(
env
)
self
.
py_index
=
CloneNode
(
self
.
index
).
coerce_to_pyobject
(
env
)
if
getting
:
env
.
use_utility_code
(
getitem_int_utility_code
)
if
setting
:
env
.
use_utility_code
(
setitem_int_utility_code
)
else
:
else
:
self
.
index
=
self
.
index
.
coerce_to_pyobject
(
env
)
self
.
index
=
self
.
index
.
coerce_to_pyobject
(
env
)
self
.
py_index
=
CloneNode
(
self
.
index
)
self
.
type
=
py_object_type
self
.
type
=
py_object_type
self
.
is_temp
=
1
self
.
is_temp
=
1
else
:
else
:
self
.
py_index
=
CloneNode
(
self
.
index
)
# so that it exists for subexpr processing
if
self
.
base
.
type
.
is_ptr
or
self
.
base
.
type
.
is_array
:
if
self
.
base
.
type
.
is_ptr
or
self
.
base
.
type
.
is_array
:
self
.
type
=
self
.
base
.
type
.
base_type
self
.
type
=
self
.
base
.
type
.
base_type
else
:
else
:
...
@@ -1281,79 +1289,63 @@ class IndexNode(ExprNode):
...
@@ -1281,79 +1289,63 @@ class IndexNode(ExprNode):
def
calculate_result_code
(
self
):
def
calculate_result_code
(
self
):
return
"(%s[%s])"
%
(
return
"(%s[%s])"
%
(
self
.
base
.
result_code
,
self
.
index
.
result_code
)
self
.
base
.
result_code
,
self
.
index
.
result_code
)
def
index_unsigned_parameter
(
self
):
if
self
.
index
.
type
.
is_int
:
if
self
.
original_index_type
.
signed
:
return
", 0"
else
:
return
", sizeof(Py_ssize_t) <= sizeof(%s)"
%
self
.
original_index_type
.
declaration_code
(
""
)
else
:
return
""
def
generate_subexpr_evaluation_code
(
self
,
code
):
def
generate_subexpr_evaluation_code
(
self
,
code
):
# do not evaluate self.py_index in case we don't need it
self
.
base
.
generate_evaluation_code
(
code
)
self
.
base
.
generate_evaluation_code
(
code
)
self
.
index
.
generate_evaluation_code
(
code
)
self
.
index
.
generate_evaluation_code
(
code
)
def
generate_subexpr_disposal_code
(
self
,
code
):
def
generate_subexpr_disposal_code
(
self
,
code
):
# if we used self.py_index, it will be disposed of manually
self
.
base
.
generate_disposal_code
(
code
)
self
.
base
.
generate_disposal_code
(
code
)
self
.
index
.
generate_disposal_code
(
code
)
self
.
index
.
generate_disposal_code
(
code
)
def
generate_result_code
(
self
,
code
):
def
generate_result_code
(
self
,
code
):
if
self
.
type
.
is_pyobject
:
if
self
.
type
.
is_pyobject
:
if
self
.
index
.
type
.
is_int
:
if
self
.
index
.
type
.
is_int
:
code
.
putln
(
"if (PyList_CheckExact(%s) && 0 <= %s && %s < PyList_GET_SIZE(%s)) {"
%
(
function
=
"__Pyx_GetItemInt"
self
.
base
.
py_result
(),
index_code
=
self
.
index
.
result_code
self
.
index
.
result_code
,
self
.
index
.
result_code
,
self
.
base
.
py_result
()))
code
.
putln
(
"%s = PyList_GET_ITEM(%s, %s); Py_INCREF(%s);"
%
(
self
.
result_code
,
self
.
base
.
py_result
(),
self
.
index
.
result_code
,
self
.
result_code
))
code
.
putln
(
"} else if (PyTuple_CheckExact(%s) && 0 <= %s && %s < PyTuple_GET_SIZE(%s)) {"
%
(
self
.
base
.
py_result
(),
self
.
index
.
result_code
,
self
.
index
.
result_code
,
self
.
base
.
py_result
()))
code
.
putln
(
"%s = PyTuple_GET_ITEM(%s, %s); Py_INCREF(%s);"
%
(
self
.
result_code
,
self
.
base
.
py_result
(),
self
.
index
.
result_code
,
self
.
result_code
))
code
.
putln
(
"} else {"
)
self
.
generate_generic_code_result
(
code
)
code
.
putln
(
"}"
)
else
:
else
:
self
.
generate_generic_code_result
(
code
)
function
=
"PyObject_GetItem"
index_code
=
self
.
index
.
py_result
()
sign_code
=
""
code
.
putln
(
"%s = %s(%s, %s%s); if (!%s) %s"
%
(
self
.
result_code
,
function
,
self
.
base
.
py_result
(),
index_code
,
self
.
index_unsigned_parameter
(),
self
.
result_code
,
code
.
error_goto
(
self
.
pos
)))
def
generate_generic_code_result
(
self
,
code
):
def
generate_setitem_code
(
self
,
value_code
,
code
):
self
.
py_index
.
generate_result_code
(
code
)
if
self
.
index
.
type
.
is_int
:
function
=
"__Pyx_SetItemInt"
index_code
=
self
.
index
.
result_code
else
:
function
=
"PyObject_SetItem"
index_code
=
self
.
index
.
py_result
()
code
.
putln
(
code
.
putln
(
"
%s = PyObject_GetItem(%s, %s);
%s"
%
(
"
if (%s(%s, %s, %s%s) < 0)
%s"
%
(
self
.
result_code
,
function
,
self
.
base
.
py_result
(),
self
.
base
.
py_result
(),
self
.
py_index
.
py_result
()
,
index_code
,
code
.
error_goto_if_null
(
self
.
result_code
,
self
.
pos
)))
value_code
,
if
self
.
is_temp
:
self
.
index_unsigned_parameter
(),
self
.
py_index
.
generate_disposal_code
(
code
)
code
.
error_goto
(
self
.
pos
))
)
def
generate_assignment_code
(
self
,
rhs
,
code
):
def
generate_assignment_code
(
self
,
rhs
,
code
):
self
.
generate_subexpr_evaluation_code
(
code
)
self
.
generate_subexpr_evaluation_code
(
code
)
if
self
.
type
.
is_pyobject
:
if
self
.
type
.
is_pyobject
:
if
self
.
index
.
type
.
is_int
:
self
.
generate_setitem_code
(
rhs
.
py_result
(),
code
)
code
.
putln
(
"if (PyList_CheckExact(%s) && 0 <= %s && %s < PyList_GET_SIZE(%s)) {"
%
(
self
.
base
.
py_result
(),
self
.
index
.
result_code
,
self
.
index
.
result_code
,
self
.
base
.
py_result
()))
code
.
putln
(
"Py_DECREF(PyList_GET_ITEM(%s, %s)); Py_INCREF(%s);"
%
(
self
.
base
.
py_result
(),
self
.
index
.
result_code
,
rhs
.
py_result
()))
code
.
putln
(
"PyList_SET_ITEM(%s, %s, %s);"
%
(
self
.
base
.
py_result
(),
self
.
index
.
result_code
,
rhs
.
py_result
()))
code
.
putln
(
"} else {"
)
self
.
generate_generic_assignment_code
(
rhs
,
code
)
code
.
putln
(
"}"
)
else
:
self
.
generate_generic_assignment_code
(
rhs
,
code
)
else
:
else
:
code
.
putln
(
code
.
putln
(
"%s = %s;"
%
(
"%s = %s;"
%
(
...
@@ -1361,25 +1353,22 @@ class IndexNode(ExprNode):
...
@@ -1361,25 +1353,22 @@ class IndexNode(ExprNode):
self
.
generate_subexpr_disposal_code
(
code
)
self
.
generate_subexpr_disposal_code
(
code
)
rhs
.
generate_disposal_code
(
code
)
rhs
.
generate_disposal_code
(
code
)
def
generate_generic_assignment_code
(
self
,
rhs
,
code
):
self
.
py_index
.
generate_result_code
(
code
)
code
.
put_error_if_neg
(
self
.
pos
,
"PyObject_SetItem(%s, %s, %s)"
%
(
self
.
base
.
py_result
(),
self
.
py_index
.
py_result
(),
rhs
.
py_result
()))
if
self
.
is_temp
:
self
.
py_index
.
generate_disposal_code
(
code
)
def
generate_deletion_code
(
self
,
code
):
def
generate_deletion_code
(
self
,
code
):
self
.
generate_subexpr_evaluation_code
(
code
)
self
.
generate_subexpr_evaluation_code
(
code
)
self
.
py_index
.
generate_evaluation_code
(
code
)
#if self.type.is_pyobject:
code
.
put_error_if_neg
(
self
.
pos
,
if
self
.
index
.
type
.
is_int
:
"PyObject_DelItem(%s, %s)"
%
(
function
=
"PySequence_DelItem"
index_code
=
self
.
index
.
result_code
else
:
function
=
"PyObject_DelItem"
index_code
=
self
.
index
.
py_result
()
code
.
putln
(
"if (%s(%s, %s) < 0) %s"
%
(
function
,
self
.
base
.
py_result
(),
self
.
base
.
py_result
(),
self
.
py_index
.
py_result
()))
index_code
,
code
.
error_goto
(
self
.
pos
)))
self
.
generate_subexpr_disposal_code
(
code
)
self
.
generate_subexpr_disposal_code
(
code
)
self
.
py_index
.
generate_disposal_code
(
code
)
class
SliceIndexNode
(
ExprNode
):
class
SliceIndexNode
(
ExprNode
):
...
@@ -2274,7 +2263,7 @@ class TupleNode(SequenceNode):
...
@@ -2274,7 +2263,7 @@ class TupleNode(SequenceNode):
# of generate_disposal_code, because values were stored
# of generate_disposal_code, because values were stored
# in the tuple using a reference-stealing operation.
# in the tuple using a reference-stealing operation.
for
arg
in
self
.
args
:
for
arg
in
self
.
args
:
arg
.
generate_post_assignment_code
(
code
)
arg
.
generate_post_assignment_code
(
code
)
class
ListNode
(
SequenceNode
):
class
ListNode
(
SequenceNode
):
...
@@ -2737,9 +2726,8 @@ class TypecastNode(ExprNode):
...
@@ -2737,9 +2726,8 @@ class TypecastNode(ExprNode):
if
from_py
and
not
to_py
and
self
.
operand
.
is_ephemeral
()
and
not
self
.
type
.
is_numeric
:
if
from_py
and
not
to_py
and
self
.
operand
.
is_ephemeral
()
and
not
self
.
type
.
is_numeric
:
error
(
self
.
pos
,
"Casting temporary Python object to non-numeric non-Python type"
)
error
(
self
.
pos
,
"Casting temporary Python object to non-numeric non-Python type"
)
if
to_py
and
not
from_py
:
if
to_py
and
not
from_py
:
self
.
result_ctype
=
py_object_type
self
.
is_temp
=
1
if
self
.
operand
.
type
.
to_py_function
:
if
self
.
operand
.
type
.
to_py_function
:
self
.
result_ctype
=
py_object_type
self
.
operand
=
self
.
operand
.
coerce_to_pyobject
(
env
)
self
.
operand
=
self
.
operand
.
coerce_to_pyobject
(
env
)
else
:
else
:
warning
(
self
.
pos
,
"No conversion from %s to %s, python object pointer used."
%
(
self
.
operand
.
type
,
self
.
type
))
warning
(
self
.
pos
,
"No conversion from %s to %s, python object pointer used."
%
(
self
.
operand
.
type
,
self
.
type
))
...
@@ -3850,9 +3838,6 @@ class CloneNode(CoercionNode):
...
@@ -3850,9 +3838,6 @@ class CloneNode(CoercionNode):
if
hasattr
(
self
.
arg
,
'entry'
):
if
hasattr
(
self
.
arg
,
'entry'
):
self
.
entry
=
self
.
arg
.
entry
self
.
entry
=
self
.
arg
.
entry
#def result_as_extension_type(self):
# return self.arg.result_as_extension_type()
def
generate_evaluation_code
(
self
,
code
):
def
generate_evaluation_code
(
self
,
code
):
pass
pass
...
@@ -4138,3 +4123,62 @@ static void __Pyx_TypeModified(PyTypeObject* type) {
...
@@ -4138,3 +4123,62 @@ static void __Pyx_TypeModified(PyTypeObject* type) {
#endif
#endif
"""
"""
]
]
#------------------------------------------------------------------------------------
# If the is_unsigned flag is set, we need to do some extra work to make
# sure the index doesn't become negative.
getitem_int_utility_code
=
[
"""
static INLINE PyObject *__Pyx_GetItemInt(PyObject *o, Py_ssize_t i, int is_unsigned) {
PyObject *r;
if (PyList_CheckExact(o) && 0 <= i && i < PyList_GET_SIZE(o)) {
r = PyList_GET_ITEM(o, i);
Py_INCREF(r);
}
else if (PyTuple_CheckExact(o) && 0 <= i && i < PyTuple_GET_SIZE(o)) {
r = PyTuple_GET_ITEM(o, i);
Py_INCREF(r);
}
else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0) || !is_unsigned))
r = PySequence_GetItem(o, i);
else {
PyObject *j = (likely(i >= 0) || !is_unsigned) ? PyInt_FromLong(i) : PyLong_FromUnsignedLongLong((sizeof(unsigned long long) > sizeof(Py_ssize_t) ? (1ULL << (sizeof(Py_ssize_t)*8)) : 0) + i);
if (!j)
return 0;
r = PyObject_GetItem(o, j);
Py_DECREF(j);
}
return r;
}
"""
,
"""
"""
]
#------------------------------------------------------------------------------------
setitem_int_utility_code
=
[
"""
static INLINE int __Pyx_SetItemInt(PyObject *o, Py_ssize_t i, PyObject *v, int is_unsigned) {
int r;
if (PyList_CheckExact(o) && 0 <= i && i < PyList_GET_SIZE(o)) {
Py_DECREF(PyList_GET_ITEM(o, i));
Py_INCREF(v);
PyList_SET_ITEM(o, i, v);
return 1;
}
else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && (likely(i >= 0) || !is_unsigned))
r = PySequence_SetItem(o, i, v);
else {
PyObject *j = (likely(i >= 0) || !is_unsigned) ? PyInt_FromLong(i) : PyLong_FromUnsignedLongLong((sizeof(unsigned long long) > sizeof(Py_ssize_t) ? (1ULL << (sizeof(Py_ssize_t)*8)) : 0) + i);
if (!j)
return -1;
r = PyObject_SetItem(o, j, v);
Py_DECREF(j);
}
return r;
}
"""
,
"""
"""
]
Cython/Compiler/Lexicon.py
View file @
7bf952b2
...
@@ -68,7 +68,9 @@ def make_lexicon():
...
@@ -68,7 +68,9 @@ def make_lexicon():
bra
=
Any
(
"([{"
)
bra
=
Any
(
"([{"
)
ket
=
Any
(
")]}"
)
ket
=
Any
(
")]}"
)
punct
=
Any
(
":,;+-*/|&<>=.%`~^?"
)
punct
=
Any
(
":,;+-*/|&<>=.%`~^?"
)
diphthong
=
Str
(
"=="
,
"<>"
,
"!="
,
"<="
,
">="
,
"<<"
,
">>"
,
"**"
,
"+="
,
"-="
,
"*="
,
"/="
,
"%="
,
"|="
,
"^="
,
"&="
,
"//"
)
diphthong
=
Str
(
"=="
,
"<>"
,
"!="
,
"<="
,
">="
,
"<<"
,
">>"
,
"**"
,
"//"
,
"+="
,
"-="
,
"*="
,
"/="
,
"%="
,
"|="
,
"^="
,
"&="
,
"<<="
,
">>="
,
"**="
,
"//="
)
spaces
=
Rep1
(
Any
(
"
\
t
\
f
"
))
spaces
=
Rep1
(
Any
(
"
\
t
\
f
"
))
comment
=
Str
(
"#"
)
+
Rep
(
AnyBut
(
"
\
n
"
))
comment
=
Str
(
"#"
)
+
Rep
(
AnyBut
(
"
\
n
"
))
escaped_newline
=
Str
(
"
\
\
\
n
"
)
escaped_newline
=
Str
(
"
\
\
\
n
"
)
...
...
Cython/Compiler/ModuleNode.py
View file @
7bf952b2
...
@@ -230,6 +230,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -230,6 +230,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self
.
generate_typeobj_definitions
(
env
,
code
)
self
.
generate_typeobj_definitions
(
env
,
code
)
self
.
generate_method_table
(
env
,
code
)
self
.
generate_method_table
(
env
,
code
)
self
.
generate_filename_init_prototype
(
code
)
self
.
generate_filename_init_prototype
(
code
)
if
env
.
has_import_star
:
self
.
generate_import_star
(
env
,
code
)
self
.
generate_module_init_func
(
modules
[:
-
1
],
env
,
code
)
self
.
generate_module_init_func
(
modules
[:
-
1
],
env
,
code
)
code
.
mark_pos
(
None
)
code
.
mark_pos
(
None
)
self
.
generate_module_cleanup_func
(
env
,
code
)
self
.
generate_module_cleanup_func
(
env
,
code
)
...
@@ -1430,6 +1432,66 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -1430,6 +1432,66 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def
generate_filename_init_prototype
(
self
,
code
):
def
generate_filename_init_prototype
(
self
,
code
):
code
.
putln
(
""
);
code
.
putln
(
""
);
code
.
putln
(
"static void %s(void); /*proto*/"
%
Naming
.
fileinit_cname
)
code
.
putln
(
"static void %s(void); /*proto*/"
%
Naming
.
fileinit_cname
)
def
generate_import_star
(
self
,
env
,
code
):
code
.
putln
()
code
.
putln
(
"char* %s_type_names[] = {"
%
Naming
.
import_star
)
for
name
,
entry
in
env
.
entries
.
items
():
if
entry
.
is_type
:
code
.
putln
(
'"%s",'
%
name
)
code
.
putln
(
"0"
)
code
.
putln
(
"};"
)
code
.
putln
()
code
.
putln
(
"static int %s(PyObject *o, PyObject* py_name, char *name) {"
%
Naming
.
import_star_set
)
code
.
putln
(
"char** type_name = %s_type_names;"
%
Naming
.
import_star
)
code
.
putln
(
"while (*type_name) {"
)
code
.
putln
(
"if (!strcmp(name, *type_name)) {"
)
code
.
putln
(
'PyErr_Format(PyExc_TypeError, "Cannot overwrite C type %s", name);'
)
code
.
putln
(
'goto bad;'
)
code
.
putln
(
"}"
)
code
.
putln
(
"type_name++;"
)
code
.
putln
(
"}"
)
old_error_label
=
code
.
new_error_label
()
code
.
putln
(
"if (0);"
)
# so the first one can be "else if"
for
name
,
entry
in
env
.
entries
.
items
():
if
entry
.
is_cglobal
and
entry
.
used
:
code
.
putln
(
'else if (!strcmp(name, "%s")) {'
%
name
)
if
entry
.
type
.
is_pyobject
:
if
entry
.
type
.
is_extension_type
or
entry
.
type
.
is_builtin_type
:
code
.
putln
(
"if (!(%s)) %s;"
%
(
entry
.
type
.
type_test_code
(
"o"
),
code
.
error_goto
(
entry
.
pos
)))
code
.
put_var_decref
(
entry
)
code
.
putln
(
"%s = %s;"
%
(
entry
.
cname
,
PyrexTypes
.
typecast
(
entry
.
type
,
py_object_type
,
"o"
)))
elif
entry
.
type
.
from_py_function
:
rhs
=
"%s(o)"
%
entry
.
type
.
from_py_function
if
entry
.
type
.
is_enum
:
rhs
=
typecast
(
entry
.
type
,
c_long_type
,
rhs
)
code
.
putln
(
"%s = %s; if (%s) %s;"
%
(
entry
.
cname
,
rhs
,
entry
.
type
.
error_condition
(
entry
.
cname
),
code
.
error_goto
(
entry
.
pos
)))
code
.
putln
(
"Py_DECREF(o);"
)
else
:
code
.
putln
(
'PyErr_Format(PyExc_TypeError, "Cannot convert Python object %s to %s");'
%
(
name
,
entry
.
type
))
code
.
putln
(
code
.
error_goto
(
entry
.
pos
))
code
.
putln
(
"}"
)
code
.
putln
(
"else {"
)
code
.
putln
(
"if (PyObject_SetAttr(%s, py_name, o) < 0) goto bad;"
%
Naming
.
module_cname
)
code
.
putln
(
"}"
)
code
.
putln
(
"return 0;"
)
code
.
put_label
(
code
.
error_label
)
# This helps locate the offending name.
code
.
putln
(
'__Pyx_AddTraceback("%s");'
%
self
.
full_module_name
);
code
.
error_label
=
old_error_label
code
.
putln
(
"bad:"
)
code
.
putln
(
"Py_DECREF(o);"
)
code
.
putln
(
"return -1;"
)
code
.
putln
(
"}"
)
code
.
putln
(
import_star_utility_code
)
def
generate_module_init_func
(
self
,
imported_modules
,
env
,
code
):
def
generate_module_init_func
(
self
,
imported_modules
,
env
,
code
):
code
.
putln
(
""
)
code
.
putln
(
""
)
...
@@ -1544,6 +1606,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -1544,6 +1606,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"if (!%s) %s;"
%
(
"if (!%s) %s;"
%
(
env
.
module_cname
,
env
.
module_cname
,
code
.
error_goto
(
self
.
pos
)));
code
.
error_goto
(
self
.
pos
)));
code
.
putln
(
"Py_INCREF(%s);"
%
env
.
module_cname
)
code
.
putln
(
code
.
putln
(
'%s = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME);'
%
'%s = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME);'
%
Naming
.
builtins_cname
)
Naming
.
builtins_cname
)
...
@@ -2017,3 +2082,94 @@ bad:
...
@@ -2017,3 +2082,94 @@ bad:
return ret;
return ret;
}
}
"""
]
"""
]
import_star_utility_code
=
"""
/* import_all_from is an unexposed function from ceval.c */
static int
__Pyx_import_all_from(PyObject *locals, PyObject *v)
{
PyObject *all = PyObject_GetAttrString(v, "__all__");
PyObject *dict, *name, *value;
int skip_leading_underscores = 0;
int pos, err;
if (all == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1; /* Unexpected error */
PyErr_Clear();
dict = PyObject_GetAttrString(v, "__dict__");
if (dict == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_SetString(PyExc_ImportError,
"from-import-* object has no __dict__ and no __all__");
return -1;
}
all = PyMapping_Keys(dict);
Py_DECREF(dict);
if (all == NULL)
return -1;
skip_leading_underscores = 1;
}
for (pos = 0, err = 0; ; pos++) {
name = PySequence_GetItem(all, pos);
if (name == NULL) {
if (!PyErr_ExceptionMatches(PyExc_IndexError))
err = -1;
else
PyErr_Clear();
break;
}
if (skip_leading_underscores &&
PyString_Check(name) &&
PyString_AS_STRING(name)[0] == '_')
{
Py_DECREF(name);
continue;
}
value = PyObject_GetAttr(v, name);
if (value == NULL)
err = -1;
else if (PyDict_CheckExact(locals))
err = PyDict_SetItem(locals, name, value);
else
err = PyObject_SetItem(locals, name, value);
Py_DECREF(name);
Py_XDECREF(value);
if (err != 0)
break;
}
Py_DECREF(all);
return err;
}
static int %s(PyObject* m) {
int i;
int ret = -1;
PyObject *locals = 0;
PyObject *list = 0;
PyObject *name;
PyObject *item;
locals = PyDict_New(); if (!locals) goto bad;
if (__Pyx_import_all_from(locals, m) < 0) goto bad;
list = PyDict_Items(locals); if (!list) goto bad;
for(i=0; i<PyList_GET_SIZE(list); i++) {
name = PyTuple_GET_ITEM(PyList_GET_ITEM(list, i), 0);
item = PyTuple_GET_ITEM(PyList_GET_ITEM(list, i), 1);
if (%s(item, name, PyString_AsString(name)) < 0) goto bad;
}
ret = 0;
bad:
Py_XDECREF(locals);
Py_XDECREF(list);
return ret;
}
"""
%
(
Naming
.
import_star
,
Naming
.
import_star_set
)
Cython/Compiler/Naming.py
View file @
7bf952b2
...
@@ -67,6 +67,8 @@ print_function_kwargs = pyrex_prefix + "print_kwargs"
...
@@ -67,6 +67,8 @@ print_function_kwargs = pyrex_prefix + "print_kwargs"
cleanup_cname
=
pyrex_prefix
+
"module_cleanup"
cleanup_cname
=
pyrex_prefix
+
"module_cleanup"
optional_args_cname
=
pyrex_prefix
+
"optional_args"
optional_args_cname
=
pyrex_prefix
+
"optional_args"
no_opt_args
=
pyrex_prefix
+
"no_opt_args"
no_opt_args
=
pyrex_prefix
+
"no_opt_args"
import_star
=
pyrex_prefix
+
"import_star"
import_star_set
=
pyrex_prefix
+
"import_star_set"
line_c_macro
=
"__LINE__"
line_c_macro
=
"__LINE__"
...
...
Cython/Compiler/Nodes.py
View file @
7bf952b2
...
@@ -2440,21 +2440,34 @@ class InPlaceAssignmentNode(AssignmentNode):
...
@@ -2440,21 +2440,34 @@ class InPlaceAssignmentNode(AssignmentNode):
self
.
rhs
.
generate_evaluation_code
(
code
)
self
.
rhs
.
generate_evaluation_code
(
code
)
self
.
dup
.
generate_subexpr_evaluation_code
(
code
)
self
.
dup
.
generate_subexpr_evaluation_code
(
code
)
self
.
dup
.
generate_result_code
(
code
)
self
.
dup
.
generate_result_code
(
code
)
if
self
.
operator
==
"**"
:
extra
=
", Py_None"
else
:
extra
=
""
if
self
.
lhs
.
type
.
is_pyobject
:
if
self
.
lhs
.
type
.
is_pyobject
:
code
.
putln
(
code
.
putln
(
"%s = %s(%s, %s); %s"
%
(
"%s = %s(%s, %s
%s
); %s"
%
(
self
.
result
.
result_code
,
self
.
result
.
result_code
,
self
.
py_operation_function
(),
self
.
py_operation_function
(),
self
.
dup
.
py_result
(),
self
.
dup
.
py_result
(),
self
.
rhs
.
py_result
(),
self
.
rhs
.
py_result
(),
extra
,
code
.
error_goto_if_null
(
self
.
result
.
py_result
(),
self
.
pos
)))
code
.
error_goto_if_null
(
self
.
result
.
py_result
(),
self
.
pos
)))
self
.
result
.
generate_evaluation_code
(
code
)
# May be a type check...
self
.
result
.
generate_evaluation_code
(
code
)
# May be a type check...
self
.
rhs
.
generate_disposal_code
(
code
)
self
.
rhs
.
generate_disposal_code
(
code
)
self
.
dup
.
generate_disposal_code
(
code
)
self
.
dup
.
generate_disposal_code
(
code
)
self
.
lhs
.
generate_assignment_code
(
self
.
result
,
code
)
self
.
lhs
.
generate_assignment_code
(
self
.
result
,
code
)
else
:
else
:
c_op
=
self
.
operator
if
c_op
==
"//"
:
c_op
=
"/"
elif
c_op
==
"**"
:
if
self
.
lhs
.
type
.
is_int
and
self
.
rhs
.
type
.
is_int
:
error
(
self
.
pos
,
"** with two C int types is ambiguous"
)
else
:
error
(
self
.
pos
,
"No C inplace power operator"
)
# have to do assignment directly to avoid side-effects
# have to do assignment directly to avoid side-effects
code
.
putln
(
"%s %s= %s;"
%
(
self
.
lhs
.
result_code
,
self
.
operator
,
self
.
rhs
.
result_code
)
)
code
.
putln
(
"%s %s= %s;"
%
(
self
.
lhs
.
result_code
,
c_op
,
self
.
rhs
.
result_code
)
)
self
.
rhs
.
generate_disposal_code
(
code
)
self
.
rhs
.
generate_disposal_code
(
code
)
if
self
.
dup
.
is_temp
:
if
self
.
dup
.
is_temp
:
self
.
dup
.
generate_subexpr_disposal_code
(
code
)
self
.
dup
.
generate_subexpr_disposal_code
(
code
)
...
@@ -2484,6 +2497,10 @@ class InPlaceAssignmentNode(AssignmentNode):
...
@@ -2484,6 +2497,10 @@ class InPlaceAssignmentNode(AssignmentNode):
"*"
:
"PyNumber_InPlaceMultiply"
,
"*"
:
"PyNumber_InPlaceMultiply"
,
"/"
:
"PyNumber_InPlaceDivide"
,
"/"
:
"PyNumber_InPlaceDivide"
,
"%"
:
"PyNumber_InPlaceRemainder"
,
"%"
:
"PyNumber_InPlaceRemainder"
,
"<<"
:
"PyNumber_InPlaceLshift"
,
">>"
:
"PyNumber_InPlaceRshift"
,
"**"
:
"PyNumber_InPlacePower"
,
"//"
:
"PyNumber_InPlaceFloorDivide"
,
}
}
def
annotate
(
self
,
code
):
def
annotate
(
self
,
code
):
...
@@ -3648,10 +3665,14 @@ class FromCImportStatNode(StatNode):
...
@@ -3648,10 +3665,14 @@ class FromCImportStatNode(StatNode):
module_scope
=
env
.
find_module
(
self
.
module_name
,
self
.
pos
)
module_scope
=
env
.
find_module
(
self
.
module_name
,
self
.
pos
)
env
.
add_imported_module
(
module_scope
)
env
.
add_imported_module
(
module_scope
)
for
pos
,
name
,
as_name
in
self
.
imported_names
:
for
pos
,
name
,
as_name
in
self
.
imported_names
:
entry
=
module_scope
.
find
(
name
,
pos
)
if
name
==
"*"
:
if
entry
:
for
local_name
,
entry
in
module_scope
.
entries
.
items
():
local_name
=
as_name
or
name
env
.
add_imported_entry
(
local_name
,
entry
,
pos
)
env
.
add_imported_entry
(
local_name
,
entry
,
pos
)
else
:
entry
=
module_scope
.
find
(
name
,
pos
)
if
entry
:
local_name
=
as_name
or
name
env
.
add_imported_entry
(
local_name
,
entry
,
pos
)
def
analyse_expressions
(
self
,
env
):
def
analyse_expressions
(
self
,
env
):
pass
pass
...
@@ -3667,12 +3688,21 @@ class FromImportStatNode(StatNode):
...
@@ -3667,12 +3688,21 @@ class FromImportStatNode(StatNode):
# items [(string, NameNode)]
# items [(string, NameNode)]
# interned_items [(string, NameNode)]
# interned_items [(string, NameNode)]
# item PyTempNode used internally
# item PyTempNode used internally
# import_star boolean used internally
child_attrs
=
[
"module"
]
child_attrs
=
[
"module"
]
import_star
=
0
def
analyse_declarations
(
self
,
env
):
def
analyse_declarations
(
self
,
env
):
for
_
,
target
in
self
.
items
:
for
name
,
target
in
self
.
items
:
target
.
analyse_target_declaration
(
env
)
if
name
==
"*"
:
if
not
env
.
is_module_scope
:
error
(
self
.
pos
,
"import * only allowed at module level"
)
return
env
.
has_import_star
=
1
self
.
import_star
=
1
else
:
target
.
analyse_target_declaration
(
env
)
def
analyse_expressions
(
self
,
env
):
def
analyse_expressions
(
self
,
env
):
import
ExprNodes
import
ExprNodes
...
@@ -3681,15 +3711,27 @@ class FromImportStatNode(StatNode):
...
@@ -3681,15 +3711,27 @@ class FromImportStatNode(StatNode):
self
.
item
.
allocate_temp
(
env
)
self
.
item
.
allocate_temp
(
env
)
self
.
interned_items
=
[]
self
.
interned_items
=
[]
for
name
,
target
in
self
.
items
:
for
name
,
target
in
self
.
items
:
self
.
interned_items
.
append
(
if
name
==
'*'
:
(
env
.
intern_identifier
(
name
),
target
))
for
_
,
entry
in
env
.
entries
.
items
():
target
.
analyse_target_expression
(
env
,
None
)
if
not
entry
.
is_type
and
entry
.
type
.
is_extension_type
:
#target.release_target_temp(env) # was release_temp ?!?
env
.
use_utility_code
(
ExprNodes
.
type_test_utility_code
)
break
else
:
self
.
interned_items
.
append
(
(
env
.
intern_identifier
(
name
),
target
))
target
.
analyse_target_expression
(
env
,
None
)
#target.release_target_temp(env) # was release_temp ?!?
self
.
module
.
release_temp
(
env
)
self
.
module
.
release_temp
(
env
)
self
.
item
.
release_temp
(
env
)
self
.
item
.
release_temp
(
env
)
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
self
.
module
.
generate_evaluation_code
(
code
)
self
.
module
.
generate_evaluation_code
(
code
)
if
self
.
import_star
:
code
.
putln
(
'if (%s(%s) < 0) %s;'
%
(
Naming
.
import_star
,
self
.
module
.
py_result
(),
code
.
error_goto
(
self
.
pos
)))
for
cname
,
target
in
self
.
interned_items
:
for
cname
,
target
in
self
.
interned_items
:
code
.
putln
(
code
.
putln
(
'%s = PyObject_GetAttr(%s, %s); %s'
%
(
'%s = PyObject_GetAttr(%s, %s); %s'
%
(
...
...
Cython/Compiler/Parsing.py
View file @
7bf952b2
...
@@ -755,11 +755,11 @@ def p_expression_or_assignment(s):
...
@@ -755,11 +755,11 @@ def p_expression_or_assignment(s):
s
.
next
()
s
.
next
()
expr_list
.
append
(
p_expr
(
s
))
expr_list
.
append
(
p_expr
(
s
))
if
len
(
expr_list
)
==
1
:
if
len
(
expr_list
)
==
1
:
if
re
.
match
(
"[+*/
\
%^
\
&|-]
="
,
s
.
sy
):
if
re
.
match
(
r"([+*/\
%^
\&|-]|<<|>>|\
*
\*|//)
="
,
s
.
sy
):
lhs
=
expr_list
[
0
]
lhs
=
expr_list
[
0
]
if
not
isinstance
(
lhs
,
(
ExprNodes
.
AttributeNode
,
ExprNodes
.
IndexNode
,
ExprNodes
.
NameNode
)
):
if
not
isinstance
(
lhs
,
(
ExprNodes
.
AttributeNode
,
ExprNodes
.
IndexNode
,
ExprNodes
.
NameNode
)
):
error
(
lhs
.
pos
,
"Illegal operand for inplace operation."
)
error
(
lhs
.
pos
,
"Illegal operand for inplace operation."
)
operator
=
s
.
sy
[
0
]
operator
=
s
.
sy
[
:
-
1
]
s
.
next
()
s
.
next
()
rhs
=
p_expr
(
s
)
rhs
=
p_expr
(
s
)
return
Nodes
.
InPlaceAssignmentNode
(
lhs
.
pos
,
operator
=
operator
,
lhs
=
lhs
,
rhs
=
rhs
)
return
Nodes
.
InPlaceAssignmentNode
(
lhs
.
pos
,
operator
=
operator
,
lhs
=
lhs
,
rhs
=
rhs
)
...
@@ -944,8 +944,11 @@ def p_from_import_statement(s, first_statement = 0):
...
@@ -944,8 +944,11 @@ def p_from_import_statement(s, first_statement = 0):
else
:
else
:
s
.
error
(
"Expected 'import' or 'cimport'"
)
s
.
error
(
"Expected 'import' or 'cimport'"
)
if
s
.
sy
==
'*'
:
if
s
.
sy
==
'*'
:
s
.
error
(
"'import *' not supported"
)
# s.error("'import *' not supported")
imported_names
=
[
p_imported_name
(
s
)]
imported_names
=
[(
s
.
position
(),
"*"
,
None
)]
s
.
next
()
else
:
imported_names
=
[
p_imported_name
(
s
)]
while
s
.
sy
==
','
:
while
s
.
sy
==
','
:
s
.
next
()
s
.
next
()
imported_names
.
append
(
p_imported_name
(
s
))
imported_names
.
append
(
p_imported_name
(
s
))
...
@@ -1080,9 +1083,13 @@ def p_for_bounds(s):
...
@@ -1080,9 +1083,13 @@ def p_for_bounds(s):
s
.
next
()
s
.
next
()
iterator
=
p_for_iterator
(
s
)
iterator
=
p_for_iterator
(
s
)
return
{
'target'
:
target
,
'iterator'
:
iterator
}
return
{
'target'
:
target
,
'iterator'
:
iterator
}
elif
s
.
sy
==
'from'
:
else
:
s
.
next
()
if
s
.
sy
==
'from'
:
bound1
=
p_bit_expr
(
s
)
s
.
next
()
bound1
=
p_bit_expr
(
s
)
else
:
# Support shorter "for a <= x < b" syntax
bound1
,
target
=
target
,
None
rel1
=
p_for_from_relation
(
s
)
rel1
=
p_for_from_relation
(
s
)
name2_pos
=
s
.
position
()
name2_pos
=
s
.
position
()
name2
=
p_ident
(
s
)
name2
=
p_ident
(
s
)
...
@@ -1090,12 +1097,15 @@ def p_for_bounds(s):
...
@@ -1090,12 +1097,15 @@ def p_for_bounds(s):
rel2
=
p_for_from_relation
(
s
)
rel2
=
p_for_from_relation
(
s
)
bound2
=
p_bit_expr
(
s
)
bound2
=
p_bit_expr
(
s
)
step
=
p_for_from_step
(
s
)
step
=
p_for_from_step
(
s
)
if
not
target
.
is_name
:
if
target
is
None
:
error
(
target
.
pos
,
target
=
ExprNodes
.
NameNode
(
name2_pos
,
name
=
name2
)
"Target of for-from statement must be a variable name"
)
else
:
elif
name2
!=
target
.
name
:
if
not
target
.
is_name
:
error
(
name2_pos
,
error
(
target
.
pos
,
"Variable name in for-from range does not match target"
)
"Target of for-from statement must be a variable name"
)
elif
name2
!=
target
.
name
:
error
(
name2_pos
,
"Variable name in for-from range does not match target"
)
if
rel1
[
0
]
!=
rel2
[
0
]:
if
rel1
[
0
]
!=
rel2
[
0
]:
error
(
rel2_pos
,
error
(
rel2_pos
,
"Relation directions in for-from do not match"
)
"Relation directions in for-from do not match"
)
...
@@ -1105,8 +1115,6 @@ def p_for_bounds(s):
...
@@ -1105,8 +1115,6 @@ def p_for_bounds(s):
'relation2'
:
rel2
,
'relation2'
:
rel2
,
'bound2'
:
bound2
,
'bound2'
:
bound2
,
'step'
:
step
}
'step'
:
step
}
else
:
s
.
error
(
"Expected 'in' or 'from'"
)
def
p_for_from_relation
(
s
):
def
p_for_from_relation
(
s
):
if
s
.
sy
in
inequality_relations
:
if
s
.
sy
in
inequality_relations
:
...
@@ -1286,7 +1294,7 @@ def p_DEF_statement(s):
...
@@ -1286,7 +1294,7 @@ def p_DEF_statement(s):
return
Nodes
.
PassStatNode
(
pos
)
return
Nodes
.
PassStatNode
(
pos
)
def
p_IF_statement
(
s
,
level
,
cdef_flag
,
visibility
,
api
):
def
p_IF_statement
(
s
,
level
,
cdef_flag
,
visibility
,
api
):
pos
=
s
.
position
pos
=
s
.
position
()
saved_eval
=
s
.
compile_time_eval
saved_eval
=
s
.
compile_time_eval
current_eval
=
saved_eval
current_eval
=
saved_eval
denv
=
s
.
compile_time_env
denv
=
s
.
compile_time_env
...
...
Cython/Compiler/Symtab.py
View file @
7bf952b2
...
@@ -693,8 +693,10 @@ class ModuleScope(Scope):
...
@@ -693,8 +693,10 @@ class ModuleScope(Scope):
# interned_nums [int/long] Interned numeric constants
# interned_nums [int/long] Interned numeric constants
# all_pystring_entries [Entry] Python string consts from all scopes
# all_pystring_entries [Entry] Python string consts from all scopes
# types_imported {PyrexType : 1} Set of types for which import code generated
# types_imported {PyrexType : 1} Set of types for which import code generated
# has_import_star boolean Module contains import *
is_module_scope = 1
is_module_scope = 1
has_import_star = 0
def __init__(self, name, parent_module, context):
def __init__(self, name, parent_module, context):
self.parent_module = parent_module
self.parent_module = parent_module
...
@@ -734,7 +736,10 @@ class ModuleScope(Scope):
...
@@ -734,7 +736,10 @@ class ModuleScope(Scope):
def declare_builtin(self, name, pos):
def declare_builtin(self, name, pos):
if not hasattr(__builtin__, name):
if not hasattr(__builtin__, name):
if self.outer_scope is not None:
if self.has_import_star:
entry = self.declare_var(name, py_object_type, pos)
return entry
elif self.outer_scope is not None:
return self.outer_scope.declare_builtin(name, pos)
return self.outer_scope.declare_builtin(name, pos)
else:
else:
error(pos, "
undeclared
name
not
builtin
:
%
s
"%name)
error(pos, "
undeclared
name
not
builtin
:
%
s
"%name)
...
...
tests/compile/forfromelse.pyx
View file @
7bf952b2
...
@@ -5,3 +5,8 @@ cdef void spam():
...
@@ -5,3 +5,8 @@ cdef void spam():
else
:
else
:
k
=
j
k
=
j
# new syntax
for
0
<=
i
<
10
:
j
=
i
else
:
j
=
k
tests/compile/indices.pyx
0 → 100644
View file @
7bf952b2
cdef
int
*
a
cdef
object
x
cdef
int
f
(
int
i
):
print
i
return
i
x
[
f
(
1
)]
=
3
a
[
f
(
1
)]
=
3
x
[
f
(
2
)]
+=
4
a
[
f
(
2
)]
+=
4
print
x
[
1
]
print
a
[
1
]
x
[
<
object
>
f
(
1
)]
=
15
\ No newline at end of file
tests/run/big_indices.pyx
0 → 100644
View file @
7bf952b2
__doc__
=
u"""
>>> test()
neg -1
pos 4294967294
neg
pos
neg
pos
"""
def
test
():
cdef
long
neg
=
-
1
cdef
unsigned
long
pos
=
-
2
# will be a large positive number
print
"neg"
,
neg
print
"pos"
,
pos
D
=
{
neg
:
'neg'
,
pos
:
'pos'
}
print
D
[
<
object
>
neg
]
print
D
[
<
object
>
pos
]
print
D
[
neg
]
print
D
[
pos
]
\ No newline at end of file
tests/run/inplace.pyx
0 → 100644
View file @
7bf952b2
__doc__
=
u"""
>>> f(5, 7)
29509034655744
>>> g(13, 4)
32
>>> h(56, 7)
105.0
"""
def
f
(
a
,
b
):
a
+=
b
a
*=
b
a
**=
b
return
a
def
g
(
int
a
,
int
b
):
a
-=
b
a
/=
b
a
<<=
b
return
a
def
h
(
double
a
,
double
b
):
a
/=
b
a
+=
b
a
*=
b
return
a
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