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
47c9246c
Commit
47c9246c
authored
Jun 19, 2020
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Regroup and cleanup CypclassWrapper.py imports
parent
8a6cee25
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
79 additions
and
114 deletions
+79
-114
Cython/Compiler/CypclassWrapper.py
Cython/Compiler/CypclassWrapper.py
+72
-110
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+4
-4
Cython/Compiler/Naming.py
Cython/Compiler/Naming.py
+3
-0
No files found.
Cython/Compiler/CypclassWrapper.py
View file @
47c9246c
#
# Code generation for wrapping cypclass as a Python Extension Type
#
# Will be generated:
# - a PyTypeObject definition for each user defined cypclass
# - Python wrappers for cypclass methods
# - Python getters/setters for cypclass attributes
# - Specific 'tp slots' for handling cycplass objects from Python:
# . tp_new
# . tp_init
# . tp_dealloc
# ...
#
# Functions defined here will be called from ModuleNode.py
#
# Reasons for using a separate file:
# - avoid cluttering ModuleNode.py
# - regroup common logic
# - decouple the code generation process from that of 'cdef class'
#
# Code generation for cypclass will be similar to code generation for 'cdef class' in ModuleNode.py,
# but differences are significant enough that it is better to introduce some redundancy than try to
# handle both 'cdef class' and 'cypclass' in ModuleNode.py.
# Code generation for wrapping cypclasses with cclasses
#
from
__future__
import
absolute_import
import
cython
cython
.
declare
(
Naming
=
object
,
Options
=
object
,
PyrexTypes
=
object
,
TypeSlots
=
object
,
error
=
object
,
warning
=
object
,
py_object_type
=
object
,
cy_object_type
=
object
,
UtilityCode
=
object
,
EncodedString
=
object
,
re
=
object
)
cython
.
declare
(
Naming
=
object
,
PyrexTypes
=
object
,
error
=
object
,
warning
=
object
,
EncodedString
=
object
)
from
collections
import
defaultdict
import
json
import
operator
import
os
import
re
from
.PyrexTypes
import
CPtrType
from
.
import
Future
from
.
import
Annotate
from
.
import
Code
from
.
import
CypclassWrapper
from
.
import
Naming
from
.
import
Nodes
from
.
import
Options
from
.
import
TypeSlots
from
.
import
PyrexTypes
from
.
import
Pythran
from
.
import
ExprNodes
from
.
import
Visitor
from
.Errors
import
error
,
warning
from
.PyrexTypes
import
py_object_type
,
cy_object_type
from
..Utils
import
open_new_file
,
replace_suffix
,
decode_filename
,
build_hex_version
from
.Code
import
UtilityCode
,
IncludeCode
from
.StringEncoding
import
EncodedString
from
.Pythran
import
has_np_pythran
from
.Visitor
import
VisitorTransform
,
CythonTransform
from
.ParseTreeTransforms
import
InterpretCompilerDirectives
,
AnalyseDeclarationsTransform
#
# Utilities for cypclasses
#
def
cypclass_iter
(
scope
):
"""
Recursively iterate over nested cypclasses
"""
for
entry
in
scope
.
cypclass_entries
:
yield
entry
cypclass_scope
=
entry
.
type
.
scope
if
cypclass_scope
:
for
e
in
cypclass_iter
(
cypclass_scope
):
yield
e
def
cypclass_iter_scopes
(
scope
):
"""
Recursively iterate over nested cypclasses and their associated scope
"""
for
entry
in
scope
.
cypclass_entries
:
cypclass_scope
=
entry
.
type
.
scope
yield
entry
,
cypclass_scope
if
cypclass_scope
:
for
e
,
s
in
cypclass_iter_scopes
(
cypclass_scope
):
yield
e
,
s
# cython name for underlying cypclass attribute in cypclass wrappers
underlying_name
=
EncodedString
(
"nogil_cyobject"
)
...
...
@@ -94,15 +32,15 @@ underlying_name = EncodedString("nogil_cyobject")
# - Insert additional cclass wrapper nodes by returning lists of nodes
# => must run after NormalizeTree (otherwise single statements might not be held in a list)
#
class
CypclassWrapperInjection
(
CythonTransform
):
class
CypclassWrapperInjection
(
Visitor
.
CythonTransform
):
"""
Synthesize and insert a wrapper c class at the module level for each cypclass that supports it.
- Even nested cypclasses have their wrapper at the module level.
- Must run after NormalizeTree.
- The root node passed when calling this visitor should not be lower than a ModuleNode.
"""
def
__call__
(
self
,
root
):
from
.ParseTreeTransforms
import
AnalyseDeclarationsTransform
,
InterpretCompilerDirectives
self
.
pipeline
=
[
InterpretCompilerDirectives
(
self
.
context
,
self
.
context
.
compiler_directives
),
AnalyseDeclarationsTransform
(
self
.
context
)
...
...
@@ -231,17 +169,16 @@ class CypclassWrapperInjection(CythonTransform):
pyclass
=
self
.
synthesize_wrapper_pyclass
(
node
,
cclass
,
qualified_name
,
cclass_name
,
pyclass_name
)
# allow the cclass methods to bind on instance of the pyclass
from
.ExprNodes
import
SimpleCallNode
,
AttributeNode
,
NameNode
,
BoolNode
binding_decorator
=
Nodes
.
DecoratorNode
(
node
.
pos
,
decorator
=
SimpleCallNode
(
decorator
=
ExprNodes
.
SimpleCallNode
(
node
.
pos
,
function
=
AttributeNode
(
function
=
ExprNodes
.
AttributeNode
(
node
.
pos
,
attribute
=
EncodedString
(
"binding"
),
obj
=
NameNode
(
node
.
pos
,
name
=
self
.
cython_as_name
)
obj
=
ExprNodes
.
NameNode
(
node
.
pos
,
name
=
self
.
cython_as_name
)
),
args
=
[
BoolNode
(
node
.
pos
,
value
=
True
)]
args
=
[
ExprNodes
.
BoolNode
(
node
.
pos
,
value
=
True
)]
)
)
cclass
.
decorators
=
[
binding_decorator
]
...
...
@@ -254,8 +191,6 @@ class CypclassWrapperInjection(CythonTransform):
thunk
()
def
synthesize_base_tuple
(
self
,
node
):
from
.ExprNodes
import
NameNode
,
TupleNode
node_type
=
node
.
entry
.
type
bases_args
=
[]
...
...
@@ -266,20 +201,20 @@ class CypclassWrapperInjection(CythonTransform):
# consume the first wrapped base from the iterator
first_wrapped_base
=
next
(
wrapped_bases_iterator
)
first_base_cclass_name
=
first_wrapped_base
.
wrapper_type
.
name
wrapped_first_base
=
NameNode
(
node
.
pos
,
name
=
first_base_cclass_name
)
wrapped_first_base
=
ExprNodes
.
NameNode
(
node
.
pos
,
name
=
first_base_cclass_name
)
bases_args
.
append
(
wrapped_first_base
)
# use the pyclass wrapper for the other bases
for
other_base
in
wrapped_bases_iterator
:
_
,
__
,
other_base_pyclass_name
=
self
.
type_to_names
[
other_base
]
other_base_arg
=
NameNode
(
node
.
pos
,
name
=
other_base_pyclass_name
)
other_base_arg
=
ExprNodes
.
NameNode
(
node
.
pos
,
name
=
other_base_pyclass_name
)
bases_args
.
append
(
other_base_arg
)
except
StopIteration
:
# no bases
pass
return
TupleNode
(
node
.
pos
,
args
=
bases_args
)
return
ExprNodes
.
TupleNode
(
node
.
pos
,
args
=
bases_args
)
def
synthesize_wrapper_cclass
(
self
,
node
,
cclass_name
,
qualified_name
):
...
...
@@ -324,7 +259,7 @@ class CypclassWrapperInjection(CythonTransform):
return
wrapper
def
synthesize_underlying_cyobject_attribute
(
self
,
node
):
base_type
=
cy_object_type
base_type
=
PyrexTypes
.
cy_object_type
base_type_node
=
Nodes
.
CSimpleBaseTypeNode
(
node
.
pos
,
...
...
@@ -338,7 +273,11 @@ class CypclassWrapperInjection(CythonTransform):
templates
=
None
)
underlying_name_declarator
=
Nodes
.
CNameDeclaratorNode
(
node
.
pos
,
name
=
underlying_name
,
cname
=
None
)
underlying_name_declarator
=
Nodes
.
CNameDeclaratorNode
(
node
.
pos
,
name
=
underlying_name
,
cname
=
Naming
.
cypclass_attr_cname
)
underlying_cyobject
=
Nodes
.
CVarDefNode
(
pos
=
node
.
pos
,
...
...
@@ -383,6 +322,24 @@ class CypclassWrapperInjection(CythonTransform):
return
dict_attribute
def
synthesize_underlying_assignment
(
self
,
pos
,
cast_name_node
,
self_name
,
underlying_name
,
underlying_type
):
# > reference to the self argument of the wrapper method
self_obj
=
ExprNodes
.
NameNode
(
pos
,
name
=
self_name
)
# > access the underlying cyobject from the self argument of the wrapper method
underlying_obj
=
ExprNodes
.
AttributeNode
(
pos
,
obj
=
self_obj
,
attribute
=
underlying_name
)
# > cast the underlying object back to this type
cast_operation
=
ExprNodes
.
TypecastNode
(
pos
,
type
=
underlying_type
,
operand
=
underlying_obj
,
typecheck
=
False
)
cast_assignment
=
Nodes
.
SingleAssignmentNode
(
pos
,
lhs
=
cast_name_node
,
rhs
=
cast_operation
)
return
cast_assignment
def
insert_cypclass_method_wrappers
(
self
,
node
,
cclass_name
,
stats
):
for
attr
in
node
.
attributes
:
if
isinstance
(
attr
,
Nodes
.
CFuncDefNode
):
...
...
@@ -424,9 +381,6 @@ class CypclassWrapperInjection(CythonTransform):
if
not
argtype
.
type
.
can_coerce_to_pyobject
(
self
.
module_scope
):
return
# skip c methods with Python-incompatible argument types
from
.CypclassWrapper
import
underlying_name
from
.
import
ExprNodes
# > name of the wrapping method: same name as in the original code
cfunc_name
=
cfunc_declarator
.
base
.
name
py_name
=
cfunc_name
...
...
@@ -464,26 +418,19 @@ class CypclassWrapperInjection(CythonTransform):
# > names of the arguments passed when calling the underlying method; self not included
arg_objs
=
[
ExprNodes
.
NameNode
(
arg
.
pos
,
name
=
arg
.
name
)
for
arg
in
cfunc_declarator
.
args
]
# > reference to the self argument of the wrapper method
self_obj
=
ExprNodes
.
NameNode
(
self_pos
,
name
=
self_name
)
# > access the underlying cyobject from the self argument of the wrapper method
underlying_obj
=
ExprNodes
.
AttributeNode
(
cfunc_method
.
pos
,
obj
=
self_obj
,
attribute
=
underlying_name
)
# > cast the underlying object back to this type
# > access the underlying attribute
underlying_type
=
node
.
entry
.
type
cast_operation
=
ExprNodes
.
TypecastNode
(
cfunc_method
.
pos
,
type
=
underlying_type
,
operand
=
underlying_obj
,
typecheck
=
False
underlying_obj
=
ExprNodes
.
NameNode
(
self_pos
,
name
=
underlying_name
)
underlying_assignment
=
self
.
synthesize_underlying_assignment
(
self_pos
,
underlying_obj
,
self_name
,
underlying_name
,
underlying_type
)
cast_underlying_obj
=
ExprNodes
.
NameNode
(
self_pos
,
name
=
EncodedString
(
"cast_cyobject"
))
cast_assignment
=
Nodes
.
SingleAssignmentNode
(
self_pos
,
lhs
=
cast_underlying_obj
,
rhs
=
cast_operation
)
# > access the method of the underlying object
cfunc
=
ExprNodes
.
AttributeNode
(
cfunc_method
.
pos
,
obj
=
cast_
underlying_obj
,
attribute
=
cfunc_name
)
cfunc
=
ExprNodes
.
AttributeNode
(
cfunc_method
.
pos
,
obj
=
underlying_obj
,
attribute
=
cfunc_name
)
# > call to the underlying method
c_call
=
ExprNodes
.
SimpleCallNode
(
...
...
@@ -497,7 +444,7 @@ class CypclassWrapperInjection(CythonTransform):
py_stat
=
Nodes
.
ExprStatNode
(
cfunc_method
.
pos
,
expr
=
c_call
)
else
:
py_stat
=
Nodes
.
ReturnStatNode
(
cfunc_method
.
pos
,
return_type
=
PyrexTypes
.
py_object_type
,
value
=
c_call
)
py_body
=
Nodes
.
StatListNode
(
cfunc_method
.
pos
,
stats
=
[
cast
_assignment
,
py_stat
])
py_body
=
Nodes
.
StatListNode
(
cfunc_method
.
pos
,
stats
=
[
underlying
_assignment
,
py_stat
])
# > lock around the call in checklock mode
if
node
.
lock_mode
==
'checklock'
:
...
...
@@ -505,7 +452,7 @@ class CypclassWrapperInjection(CythonTransform):
lock_node
=
Nodes
.
LockCypclassNode
(
cfunc_method
.
pos
,
state
=
'wlocked'
if
need_wlock
else
'rlocked'
,
obj
=
cast_
underlying_obj
,
obj
=
underlying_obj
,
body
=
py_body
)
py_body
=
lock_node
...
...
@@ -526,8 +473,6 @@ class CypclassWrapperInjection(CythonTransform):
def
synthesize_wrapper_pyclass
(
self
,
node
,
cclass_wrapper
,
qualified_name
,
cclass_name
,
pyclass_name
):
from
.ExprNodes
import
AttributeNode
,
NameNode
py_bases
=
self
.
synthesize_base_tuple
(
node
)
py_stats
=
[]
...
...
@@ -535,10 +480,10 @@ class CypclassWrapperInjection(CythonTransform):
if
isinstance
(
defnode
,
Nodes
.
DefNode
):
def_name
=
defnode
.
name
lhs
=
NameNode
(
defnode
.
pos
,
name
=
def_name
)
lhs
=
ExprNodes
.
NameNode
(
defnode
.
pos
,
name
=
def_name
)
rhs_obj
=
NameNode
(
defnode
.
pos
,
name
=
cclass_name
)
rhs
=
AttributeNode
(
defnode
.
pos
,
obj
=
rhs_obj
,
attribute
=
def_name
)
rhs_obj
=
ExprNodes
.
NameNode
(
defnode
.
pos
,
name
=
cclass_name
)
rhs
=
ExprNodes
.
AttributeNode
(
defnode
.
pos
,
obj
=
rhs_obj
,
attribute
=
def_name
)
stat
=
Nodes
.
SingleAssignmentNode
(
defnode
.
pos
,
lhs
=
lhs
,
rhs
=
rhs
)
py_stats
.
append
(
stat
)
...
...
@@ -557,6 +502,23 @@ class CypclassWrapperInjection(CythonTransform):
return
py_class_node
#
# Utilities for cypclasses
#
def
cypclass_iter_scopes
(
scope
):
"""
Recursively iterate over nested cypclasses and their associated scope
"""
for
entry
in
scope
.
cypclass_entries
:
cypclass_scope
=
entry
.
type
.
scope
yield
entry
,
cypclass_scope
if
cypclass_scope
:
for
e
,
s
in
cypclass_iter_scopes
(
cypclass_scope
):
yield
e
,
s
#
# Cypclass code generation
#
...
...
@@ -1058,7 +1020,7 @@ def generate_cyp_class_wrapper_definition(type, wrapper_entry, constructor_entry
cclass_wrapper_base
=
type
.
wrapped_base_type
().
wrapper_type
code
.
putln
(
"if(self) {"
)
code
.
putln
(
"%s * wrapper = new %s();"
%
(
objstruct_cname
,
objstruct_cname
))
code
.
putln
(
"((%s *)wrapper)->
nogil_cyobject = self;"
%
cclass_wrapper_base
.
objstruct_cname
)
code
.
putln
(
"((%s *)wrapper)->
%s = self;"
%
(
cclass_wrapper_base
.
objstruct_cname
,
Naming
.
cypclass_attr_cname
)
)
code
.
putln
(
"PyObject * wrapper_as_py = (PyObject *) wrapper;"
)
code
.
putln
(
"wrapper_as_py->ob_refcnt = 0;"
)
code
.
putln
(
"wrapper_as_py->ob_type = %s;"
%
type
.
wrapper_type
.
typeptr_cname
)
...
...
Cython/Compiler/ModuleNode.py
View file @
47c9246c
...
...
@@ -20,7 +20,6 @@ from .PyrexTypes import CPtrType
from
.
import
Future
from
.
import
Annotate
from
.
import
Code
from
.
import
CypclassWrapper
from
.
import
Naming
from
.
import
Nodes
from
.
import
Options
...
...
@@ -664,11 +663,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self
.
generate_exttype_vtabptr_declaration
(
entry
,
code
)
self
.
generate_exttype_final_methods_declaration
(
entry
,
code
)
from
.CypclassWrapper
import
generate_cyp_class_deferred_definitions
for
module
in
modules
:
definition
=
module
is
env
code
.
putln
(
""
)
code
.
putln
(
"/* Deferred definitions for cypclasses */"
)
CypclassWrapper
.
generate_cyp_class_deferred_definitions
(
env
,
code
,
definition
)
generate_cyp_class_deferred_definitions
(
env
,
code
,
definition
)
def
generate_declarations_for_modules
(
self
,
env
,
modules
,
globalstate
):
typecode
=
globalstate
[
'type_declarations'
]
...
...
@@ -1686,7 +1686,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# for cyp wrappers, just decrement the atomic counter of the underlying type
parent_type
=
scope
.
parent_type
if
parent_type
.
is_cyp_wrapper
:
underlying_attribute_name
=
CypclassWrapper
.
underlying_
name
underlying_attribute_name
=
Naming
.
cypclass_attr_c
name
self
.
generate_self_cast
(
scope
,
code
)
code
.
putln
(
"CyObject * p_nogil_cyobject = p->%s;"
...
...
Cython/Compiler/Naming.py
View file @
47c9246c
...
...
@@ -166,6 +166,9 @@ exc_vars = (exc_type_name, exc_value_name, exc_tb_name)
api_name
=
pyrex_prefix
+
"capi__"
# c name for underlying cypclass attribute in cypclass wrappers
cypclass_attr_cname
=
"nogil_cyobject"
# the h and api guards get changed to:
# __PYX_HAVE__FILENAME (for ascii filenames)
# __PYX_HAVE_U_PUNYCODEFILENAME (for non-ascii filenames)
...
...
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