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
b788e10a
Commit
b788e10a
authored
Aug 05, 2016
by
empyrical
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for the typeid operator
parent
a767e7e8
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
182 additions
and
4 deletions
+182
-4
Cython/Compiler/CythonScope.py
Cython/Compiler/CythonScope.py
+3
-1
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+91
-1
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+1
-0
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+2
-0
Cython/Includes/libcpp/typeindex.pxd
Cython/Includes/libcpp/typeindex.pxd
+15
-0
Cython/Includes/libcpp/typeinfo.pxd
Cython/Includes/libcpp/typeinfo.pxd
+10
-0
Cython/Parser/Grammar
Cython/Parser/Grammar
+1
-0
Cython/Utility/CppSupport.cpp
Cython/Utility/CppSupport.cpp
+2
-0
docs/src/userguide/wrapping_CPlusPlus.rst
docs/src/userguide/wrapping_CPlusPlus.rst
+24
-0
tests/run/cpp_operators.pyx
tests/run/cpp_operators.pyx
+32
-2
tests/run/cpp_operators_helper.h
tests/run/cpp_operators_helper.h
+1
-0
No files found.
Cython/Compiler/CythonScope.py
View file @
b788e10a
...
...
@@ -67,7 +67,9 @@ class CythonScope(ModuleScope):
name_path
=
qname
.
split
(
u'.'
)
scope
=
self
while
len
(
name_path
)
>
1
:
scope
=
scope
.
lookup_here
(
name_path
[
0
]).
as_module
scope
=
scope
.
lookup_here
(
name_path
[
0
])
if
scope
:
scope
=
scope
.
as_module
del
name_path
[
0
]
if
scope
is
None
:
return
None
...
...
Cython/Compiler/ExprNodes.py
View file @
b788e10a
...
...
@@ -6178,6 +6178,7 @@ class AttributeNode(ExprNode):
needs_none_check
=
True
is_memslice_transpose
=
False
is_special_lookup
=
False
is_py_attr
=
0
def
as_cython_attribute
(
self
):
if
(
isinstance
(
self
.
obj
,
NameNode
)
and
...
...
@@ -6607,7 +6608,7 @@ class AttributeNode(ExprNode):
else
:
# result_code contains what is needed, but we may need to insert
# a check and raise an exception
if
self
.
obj
.
type
.
is_extension_type
:
if
self
.
obj
.
type
and
self
.
obj
.
type
.
is_extension_type
:
pass
elif
self
.
entry
and
self
.
entry
.
is_cmethod
and
self
.
entry
.
utility_code
:
# C method implemented as function call with utility code
...
...
@@ -10140,6 +10141,8 @@ class SizeofTypeNode(SizeofNode):
def
check_type
(
self
):
arg_type
=
self
.
arg_type
if
not
arg_type
:
return
if
arg_type
.
is_pyobject
and
not
arg_type
.
is_extension_type
:
error
(
self
.
pos
,
"Cannot take sizeof Python object"
)
elif
arg_type
.
is_void
:
...
...
@@ -10184,6 +10187,93 @@ class SizeofVarNode(SizeofNode):
def
generate_result_code
(
self
,
code
):
pass
class
TypeidNode
(
ExprNode
):
# C++ typeid operator applied to a type or variable
#
# operand ExprNode
# arg_type ExprNode
# is_variable boolean
# mangle_cname string
type
=
PyrexTypes
.
error_type
subexprs
=
[
'operand'
]
arg_type
=
None
is_variable
=
None
mangle_cname
=
None
def
get_type_info_type
(
self
,
env
):
if
env
.
is_module_scope
:
env_module
=
env
else
:
env_module
=
env
.
outer_scope
for
module
in
env_module
.
cimported_modules
:
if
module
.
qualified_name
==
'libcpp.typeinfo'
:
type_info
=
module
.
lookup
(
'type_info'
)
type_info
=
PyrexTypes
.
c_ref_type
(
PyrexTypes
.
c_const_type
(
type_info
.
type
))
return
type_info
return
None
def
analyse_types
(
self
,
env
):
type_info
=
self
.
get_type_info_type
(
env
)
if
not
type_info
:
self
.
error
(
"The 'libcpp.typeinfo' module must be cimported to use the typeid() operator"
)
return
self
self
.
type
=
type_info
as_type
=
self
.
operand
.
analyse_as_type
(
env
)
if
as_type
:
self
.
arg_type
=
as_type
self
.
is_type
=
True
else
:
self
.
arg_type
=
self
.
operand
.
analyse_types
(
env
)
self
.
is_type
=
False
if
self
.
arg_type
.
type
.
is_pyobject
:
self
.
error
(
"Cannot use typeid on a Python object"
)
return
self
elif
self
.
arg_type
.
type
.
is_void
:
self
.
error
(
"Cannot use typeid on void"
)
return
self
elif
not
self
.
arg_type
.
type
.
is_complete
():
self
.
error
(
"Cannot use typeid on incomplete type '%s'"
%
self
.
arg_type
.
type
)
return
self
if
env
.
is_module_scope
:
env_module
=
env
else
:
env_module
=
env
.
outer_scope
env_module
.
typeid_variables
+=
1
self
.
mangle_cname
=
"%s_typeid_%s"
%
(
env_module
.
module_cname
,
env_module
.
typeid_variables
)
env
.
use_utility_code
(
UtilityCode
.
load_cached
(
"CppExceptionConversion"
,
"CppSupport.cpp"
))
return
self
def
error
(
self
,
mess
):
error
(
self
.
pos
,
mess
)
self
.
type
=
PyrexTypes
.
error_type
self
.
result_code
=
"<error>"
def
check_const
(
self
):
return
True
def
calculate_result_code
(
self
):
return
"(*%s)"
%
self
.
mangle_cname
def
generate_result_code
(
self
,
code
):
if
self
.
is_type
:
if
self
.
arg_type
.
is_extension_type
:
# the size of the pointer is boring
# we want the size of the actual struct
arg_code
=
self
.
arg_type
.
declaration_code
(
""
,
deref
=
1
)
else
:
arg_code
=
self
.
arg_type
.
empty_declaration_code
()
else
:
arg_code
=
self
.
arg_type
.
result
()
code
.
putln
(
"const std::type_info *%s;"
%
self
.
mangle_cname
)
translate_cpp_exception
(
code
,
self
.
pos
,
"%s = &typeid(%s);"
%
(
self
.
mangle_cname
,
arg_code
),
None
,
self
.
in_nogil_context
)
class
TypeofNode
(
ExprNode
):
# Compile-time type of an expression, as a string.
#
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
b788e10a
...
...
@@ -635,6 +635,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
'operator.predecrement'
:
ExprNodes
.
inc_dec_constructor
(
True
,
'--'
),
'operator.postincrement'
:
ExprNodes
.
inc_dec_constructor
(
False
,
'++'
),
'operator.postdecrement'
:
ExprNodes
.
inc_dec_constructor
(
False
,
'--'
),
'operator.typeid'
:
ExprNodes
.
TypeidNode
,
# For backwards compatibility.
'address'
:
ExprNodes
.
AmpersandNode
,
...
...
Cython/Compiler/Symtab.py
View file @
b788e10a
...
...
@@ -1030,6 +1030,7 @@ class ModuleScope(Scope):
# cpp boolean Compiling a C++ file
# is_cython_builtin boolean Is this the Cython builtin scope (or a child scope)
# is_package boolean Is this a package module? (__init__)
# typeid_variables int Used by the typeid() exception handler
is_module_scope
=
1
has_import_star
=
0
...
...
@@ -1069,6 +1070,7 @@ class ModuleScope(Scope):
self
.
cached_builtins
=
[]
self
.
undeclared_cached_builtins
=
[]
self
.
namespace_cname
=
self
.
module_cname
self
.
typeid_variables
=
0
self
.
_cached_tuple_types
=
{}
for
var_name
in
[
'__builtins__'
,
'__name__'
,
'__file__'
,
'__doc__'
,
'__path__'
]:
self
.
declare_var
(
EncodedString
(
var_name
),
py_object_type
,
None
)
...
...
Cython/Includes/libcpp/typeindex.pxd
0 → 100644
View file @
b788e10a
from
libcpp
cimport
bool
from
.typeinfo
cimport
type_info
# This class is C++11-only
cdef
extern
from
"<typeindex>"
namespace
"std"
nogil
:
cdef
cppclass
type_index
:
type_index
(
const
type_info
&
)
const
char
*
name
()
size_t
hash_code
()
bool
operator
==
(
const
type_index
&
)
bool
operator
!=
(
const
type_index
&
)
bool
operator
<
(
const
type_index
&
)
bool
operator
<=
(
const
type_index
&
)
bool
operator
>
(
const
type_index
&
)
bool
operator
>=
(
const
type_index
&
)
Cython/Includes/libcpp/typeinfo.pxd
0 → 100644
View file @
b788e10a
from
libcpp
cimport
bool
cdef
extern
from
"<typeinfo>"
namespace
"std"
nogil
:
cdef
cppclass
type_info
:
const
char
*
name
()
int
before
(
const
type_info
&
)
bool
operator
==
(
const
type_info
&
)
bool
operator
!=
(
const
type_info
&
)
# C++11-only
size_t
hash_code
()
Cython/Parser/Grammar
View file @
b788e10a
...
...
@@ -167,6 +167,7 @@ memory_view_index: ':' [':'] [NUMBER]
address: '&' factor
cast: '<' type ['?'] '>' factor
size_of: 'sizeof' '(' (type) ')'
type_id: 'typeid' '(' (type) ')'
new_expr: 'new' type '(' [arglist] ')'
# TODO: Restrict cdef_stmt to "top-level" statements.
...
...
Cython/Utility/CppSupport.cpp
View file @
b788e10a
...
...
@@ -18,6 +18,8 @@ static void __Pyx_CppExn2PyErr() {
PyErr_SetString
(
PyExc_MemoryError
,
exn
.
what
());
}
catch
(
const
std
::
bad_cast
&
exn
)
{
PyErr_SetString
(
PyExc_TypeError
,
exn
.
what
());
}
catch
(
const
std
::
bad_typeid
&
exn
)
{
PyErr_SetString
(
PyExc_TypeError
,
exn
.
what
());
}
catch
(
const
std
::
domain_error
&
exn
)
{
PyErr_SetString
(
PyExc_ValueError
,
exn
.
what
());
}
catch
(
const
std
::
invalid_argument
&
exn
)
{
...
...
docs/src/userguide/wrapping_CPlusPlus.rst
View file @
b788e10a
...
...
@@ -545,6 +545,8 @@ The translation is performed according to the following table
+-----------------------+---------------------+
| ``bad_cast`` | ``TypeError`` |
+-----------------------+---------------------+
| ``bad_typeid`` | ``TypeError`` |
+-----------------------+---------------------+
| ``domain_error`` | ``ValueError`` |
+-----------------------+---------------------+
| ``invalid_argument`` | ``ValueError`` |
...
...
@@ -601,6 +603,28 @@ you can declare it using the Python @staticmethod decorator, i.e.::
@staticmethod
void do_something()
RTTI and typeid()
=================
Cython has support for the ``typeid(...)`` operator. To use it, you need to import
it and the ``libcpp.typeinfo`` module first:
from cython.operator cimport typeid
from libcpp.typeinfo cimport type_info
The ``typeid(...)`` operator returns an object of the type ``const type_info &``.
If you want to store a type_info value in a C variable, you will need to store it
as a pointer rather than a reference:
cdef const type_info* info = &typeid(MyClass)
If an invalid type is passed to ``typeid``, it will throw an ``std::bad_typeid``
exception which is converted into a ``TypeError`` exception in Python.
An additional C++11-only RTTI-related class, ``std::type_index``, is available
in ``libcpp.typeindex``.
Caveats and Limitations
========================
...
...
tests/run/cpp_operators.pyx
View file @
b788e10a
...
...
@@ -4,10 +4,11 @@
from
cython
cimport
typeof
cimport
cython.operator
from
cython.operator
cimport
dereference
as
deref
from
cython.operator
cimport
typeid
,
dereference
as
deref
from
libc.string
cimport
const_char
from
libcpp
cimport
bool
cimport
libcpp.typeinfo
cdef
out
(
s
,
result_type
=
None
):
print
'%s [%s]'
%
(
s
.
decode
(
'ascii'
),
result_type
)
...
...
@@ -50,12 +51,15 @@ cdef extern from "cpp_operators_helper.h":
const_char
*
operator
[](
int
)
const_char
*
operator
()(
int
)
cppclass
TruthClass
:
c
def
c
ppclass
TruthClass
:
TruthClass
()
TruthClass
(
bool
)
bool
operator
bool
()
bool
value
cdef
cppclass
TruthSubClass
(
TruthClass
):
pass
def
test_unops
():
"""
>>> test_unops()
...
...
@@ -182,3 +186,29 @@ def test_bool_cond():
assert
(
TruthClass
(
False
)
and
TruthClass
(
True
)).
value
==
False
assert
(
TruthClass
(
True
)
and
TruthClass
(
False
)).
value
==
False
assert
(
TruthClass
(
True
)
and
TruthClass
(
True
)).
value
==
True
def
test_typeid_op
():
"""
>>> test_typeid_op()
"""
cdef
TruthClass
*
test_1
=
new
TruthClass
()
cdef
TruthSubClass
*
test_2
=
new
TruthSubClass
()
cdef
TruthClass
*
test_3
=
<
TruthClass
*>
test_2
cdef
TruthClass
*
test_4
=
<
TruthClass
*>
0
assert
typeid
(
TruthClass
).
name
()
assert
typeid
(
test_1
).
name
()
assert
typeid
(
TruthSubClass
).
name
()
assert
typeid
(
test_2
).
name
()
assert
typeid
(
TruthClass
).
name
()
assert
typeid
(
test_3
).
name
()
assert
typeid
(
TruthSubClass
).
name
()
assert
typeid
(
deref
(
test_2
)).
name
()
try
:
typeid
(
deref
(
test_4
))
assert
False
except
TypeError
:
assert
True
del
test_1
,
test_2
tests/run/cpp_operators_helper.h
View file @
b788e10a
...
...
@@ -50,6 +50,7 @@ class TruthClass {
public:
TruthClass
()
:
value
(
false
)
{}
TruthClass
(
bool
value
)
:
value
(
value
)
{}
virtual
~
TruthClass
()
{};
operator
bool
()
{
return
value
;
}
bool
value
;
};
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