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
Xavier Thompson
cython
Commits
70f6d6e5
Commit
70f6d6e5
authored
4 years ago
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make dedicated node for cypclass wrapping c class
parent
3b6b2475
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
137 additions
and
163 deletions
+137
-163
Cython/Compiler/CypclassWrapper.py
Cython/Compiler/CypclassWrapper.py
+2
-23
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+134
-138
Cython/Compiler/Pipeline.py
Cython/Compiler/Pipeline.py
+1
-2
No files found.
Cython/Compiler/CypclassWrapper.py
View file @
70f6d6e5
...
...
@@ -167,7 +167,7 @@ class CypclassWrapperInjection(VisitorTransform):
cclass_body
=
Nodes
.
StatListNode
(
pos
=
node
.
pos
,
stats
=
stats
)
cclass_doc
=
EncodedString
(
"Python Object wrapper for underlying cypclass %s"
%
node
.
name
)
wrapper
=
Nodes
.
C
Class
DefNode
(
wrapper
=
Nodes
.
C
ypclassWrapper
DefNode
(
node
.
pos
,
visibility
=
'private'
,
typedef_flag
=
0
,
...
...
@@ -182,10 +182,9 @@ class CypclassWrapperInjection(VisitorTransform):
in_pxd
=
node
.
in_pxd
,
doc
=
cclass_doc
,
body
=
cclass_body
,
is_cyp_wrapper
=
1
wrapped_cypclass
=
node
)
node
.
cyp_wrapper
=
wrapper
return
wrapper
def
synthesize_underlying_cyobject_attribute
(
self
,
node
):
...
...
@@ -219,26 +218,6 @@ class CypclassWrapperInjection(VisitorTransform):
return
underlying_cyobject
#
# Post declaration analysis visitor for wrapped cypclasses
#
# - Associate the type of the wrapper cclass to the wrapped type
# => must run after AnalyseDeclarationsTransform
#
class
CypclassPostDeclarationsVisitor
(
CythonTransform
):
"""
Associate the type of each wrapper cclass to the wrapped type.
- Must run after the declarations analysis phase.
"""
# associate the type of the wrapper cclass to the type of the wrapped cypclass
def
visit_CppClassNode
(
self
,
node
):
if
node
.
cypclass
and
node
.
cyp_wrapper
:
node
.
entry
.
type
.
wrapper_type
=
node
.
cyp_wrapper
.
entry
.
type
self
.
visitchildren
(
node
)
return
node
#
# Cypclass code generation
...
...
This diff is collapsed.
Click to expand it.
Cython/Compiler/Nodes.py
View file @
70f6d6e5
...
...
@@ -1508,13 +1508,10 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
# cypclass boolean
# lock_mode 'nolock', 'checklock', 'autolock', or None
# activable boolean
# cyp_wrapper CClassDefNode or None
decorators
=
None
scope
=
None
template_types
=
None
cyp_wrapper
=
None
def
declare
(
self
,
env
):
...
...
@@ -1623,141 +1620,6 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
for
thunk
in
self
.
entry
.
type
.
deferred_declarations
:
thunk
()
self
.
insert_cypclass_method_wrappers
(
env
)
def
insert_cypclass_method_wrappers
(
self
,
env
):
if
self
.
cyp_wrapper
:
for
attr
in
self
.
attributes
:
if
isinstance
(
attr
,
CFuncDefNode
):
py_method_wrapper
=
self
.
synthesize_cypclass_method_wrapper
(
attr
,
env
)
if
py_method_wrapper
:
# the wrapper cclasses are inserted after the wrapped node
# so their declaration analysis will still occur
self
.
cyp_wrapper
.
body
.
stats
.
append
(
py_method_wrapper
)
def
synthesize_cypclass_method_wrapper
(
self
,
cfunc_method
,
env
):
if
cfunc_method
.
is_static_method
:
return
# for now skip static methods
alternatives
=
cfunc_method
.
entry
.
all_alternatives
()
if
len
(
alternatives
)
>
1
:
return
# for now skip overloaded methods
cfunc_declarator
=
cfunc_method
.
cfunc_declarator
# > c++ methods have an implict 'this', so the 'self' argument is skipped in the declarator
skipped_self
=
cfunc_declarator
.
skipped_self
if
not
skipped_self
:
return
# if this ever happens (?), skip non-static methods without a self argument
cfunc_type
=
cfunc_method
.
type
cfunc_return_type
=
cfunc_type
.
return_type
# > TODO: the Python-incompatibility is too conservative:
# some types have not yet resolved that they can coerce to PyObject
# in particular, any cypclass not yet examined ?
if
cfunc_return_type
.
is_cyp_class
:
if
cfunc_return_type
.
templates
:
return
# only skip templated cypclasses for now
# we pass the global scope as argument, should not affect the result (?)
elif
not
cfunc_return_type
.
can_coerce_to_pyobject
(
env
.
global_scope
()):
return
# skip c methods with Python-incompatible return types
for
argtype
in
cfunc_type
.
args
:
if
argtype
.
type
.
is_cyp_class
:
if
argtype
.
type
.
templates
:
return
# only skip templated cypclasses for now
elif
not
argtype
.
type
.
can_coerce_to_pyobject
(
env
.
global_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
# > self argument of the wrapper method: same name, but type of the wrapper cclass
self_name
,
self_type
,
self_pos
,
self_arg
=
skipped_self
py_self_arg
=
CArgDeclNode
(
self_pos
,
base_type
=
CSimpleBaseTypeNode
(
self_pos
,
name
=
self
.
cyp_wrapper
.
class_name
,
module_path
=
[],
signed
=
1
,
is_basic_c_type
=
0
,
longness
=
0
,
is_self_arg
=
0
,
# only true for C methods
templates
=
None
),
declarator
=
CNameDeclaratorNode
(
self_pos
,
name
=
self_name
,
cname
=
None
),
not_none
=
0
,
or_none
=
0
,
default
=
None
,
annotation
=
None
,
kw_only
=
0
)
# > all arguments of the wrapper method declaration
py_args
=
[
py_self_arg
]
for
arg
in
cfunc_declarator
.
args
:
py_args
.
append
(
arg
.
clone_node
())
# > same docstring
py_doc
=
cfunc_method
.
doc
# > 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 method of the underlying cyobject from the self argument of the wrapper method
underlying_obj
=
ExprNodes
.
AttributeNode
(
cfunc_method
.
pos
,
obj
=
self_obj
,
attribute
=
underlying_name
)
cfunc
=
ExprNodes
.
AttributeNode
(
cfunc_method
.
pos
,
obj
=
underlying_obj
,
attribute
=
cfunc_name
)
# > call to the underlying method
c_call
=
ExprNodes
.
SimpleCallNode
(
cfunc_method
.
pos
,
function
=
cfunc
,
args
=
arg_objs
)
# > return the result of the call if the underlying return type is not void
if
cfunc_return_type
.
is_void
:
py_stat
=
ExprStatNode
(
cfunc_method
.
pos
,
expr
=
c_call
)
else
:
py_stat
=
ReturnStatNode
(
cfunc_method
.
pos
,
return_type
=
PyrexTypes
.
py_object_type
,
value
=
c_call
)
py_body
=
StatListNode
(
cfunc_method
.
pos
,
stats
=
[
py_stat
])
# > lock around the call in checklock mode
if
self
.
lock_mode
==
'checklock'
:
need_wlock
=
not
cfunc_type
.
is_const_method
lock_node
=
LockCypclassNode
(
cfunc_method
.
pos
,
state
=
'wlocked'
if
need_wlock
else
'rlocked'
,
obj
=
underlying_obj
,
body
=
py_body
)
py_body
=
lock_node
# > the wrapper method
return
DefNode
(
cfunc_method
.
pos
,
name
=
py_name
,
args
=
py_args
,
star_arg
=
None
,
starstar_arg
=
None
,
doc
=
py_doc
,
body
=
py_body
,
decorators
=
None
,
is_async_def
=
0
,
return_type_annotation
=
None
)
def
analyse_expressions
(
self
,
env
):
self
.
body
=
self
.
body
.
analyse_expressions
(
self
.
entry
.
type
.
scope
)
return
self
...
...
@@ -5665,6 +5527,140 @@ class CClassDefNode(ClassDefNode):
self
.
body
.
annotate
(
code
)
class
CypclassWrapperDefNode
(
CClassDefNode
):
# wrapped_cypclass CppClassNode The wrapped cypclass
is_cyp_wrapper
=
1
def
analyse_declarations
(
self
,
env
):
# > analyse declarations before inserting methods
super
(
CypclassWrapperDefNode
,
self
).
analyse_declarations
(
env
)
# > associate the wrapper type to the wrapped type
self
.
wrapped_cypclass
.
entry
.
type
.
wrapper_type
=
self
.
entry
.
type
# > insert and analyse each method wrapper
self
.
insert_cypclass_method_wrappers
(
env
)
def
insert_cypclass_method_wrappers
(
self
,
env
):
for
attr
in
self
.
wrapped_cypclass
.
attributes
:
if
isinstance
(
attr
,
CFuncDefNode
):
py_method_wrapper
=
self
.
synthesize_cypclass_method_wrapper
(
attr
,
env
)
if
py_method_wrapper
:
self
.
body
.
stats
.
append
(
py_method_wrapper
)
py_method_wrapper
.
analyse_declarations
(
self
.
scope
)
def
synthesize_cypclass_method_wrapper
(
self
,
cfunc_method
,
env
):
if
cfunc_method
.
is_static_method
:
return
# for now skip static methods
alternatives
=
cfunc_method
.
entry
.
all_alternatives
()
if
len
(
alternatives
)
>
1
:
return
# for now skip overloaded methods
cfunc_declarator
=
cfunc_method
.
cfunc_declarator
# > c++ methods have an implict 'this', so the 'self' argument is skipped in the declarator
skipped_self
=
cfunc_declarator
.
skipped_self
if
not
skipped_self
:
return
# if this ever happens (?), skip non-static methods without a self argument
cfunc_type
=
cfunc_method
.
type
cfunc_return_type
=
cfunc_type
.
return_type
# we pass the global scope as argument, should not affect the result (?)
if
not
cfunc_return_type
.
can_coerce_to_pyobject
(
env
.
global_scope
()):
return
# skip c methods with Python-incompatible return types
for
argtype
in
cfunc_type
.
args
:
if
not
argtype
.
type
.
can_coerce_to_pyobject
(
env
.
global_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
# > self argument of the wrapper method: same name, but type of the wrapper cclass
self_name
,
self_type
,
self_pos
,
self_arg
=
skipped_self
py_self_arg
=
CArgDeclNode
(
self_pos
,
base_type
=
CSimpleBaseTypeNode
(
self_pos
,
name
=
self
.
class_name
,
module_path
=
[],
signed
=
1
,
is_basic_c_type
=
0
,
longness
=
0
,
is_self_arg
=
0
,
# only true for C methods
templates
=
None
),
declarator
=
CNameDeclaratorNode
(
self_pos
,
name
=
self_name
,
cname
=
None
),
not_none
=
0
,
or_none
=
0
,
default
=
None
,
annotation
=
None
,
kw_only
=
0
)
# > all arguments of the wrapper method declaration
py_args
=
[
py_self_arg
]
for
arg
in
cfunc_declarator
.
args
:
py_args
.
append
(
arg
.
clone_node
())
# > same docstring
py_doc
=
cfunc_method
.
doc
# > 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 method of the underlying cyobject from the self argument of the wrapper method
underlying_obj
=
ExprNodes
.
AttributeNode
(
cfunc_method
.
pos
,
obj
=
self_obj
,
attribute
=
underlying_name
)
cfunc
=
ExprNodes
.
AttributeNode
(
cfunc_method
.
pos
,
obj
=
underlying_obj
,
attribute
=
cfunc_name
)
# > call to the underlying method
c_call
=
ExprNodes
.
SimpleCallNode
(
cfunc_method
.
pos
,
function
=
cfunc
,
args
=
arg_objs
)
# > return the result of the call if the underlying return type is not void
if
cfunc_return_type
.
is_void
:
py_stat
=
ExprStatNode
(
cfunc_method
.
pos
,
expr
=
c_call
)
else
:
py_stat
=
ReturnStatNode
(
cfunc_method
.
pos
,
return_type
=
PyrexTypes
.
py_object_type
,
value
=
c_call
)
py_body
=
StatListNode
(
cfunc_method
.
pos
,
stats
=
[
py_stat
])
# > lock around the call in checklock mode
if
self
.
wrapped_cypclass
.
lock_mode
==
'checklock'
:
need_wlock
=
not
cfunc_type
.
is_const_method
lock_node
=
LockCypclassNode
(
cfunc_method
.
pos
,
state
=
'wlocked'
if
need_wlock
else
'rlocked'
,
obj
=
underlying_obj
,
body
=
py_body
)
py_body
=
lock_node
# > the wrapper method
return
DefNode
(
cfunc_method
.
pos
,
name
=
py_name
,
args
=
py_args
,
star_arg
=
None
,
starstar_arg
=
None
,
doc
=
py_doc
,
body
=
py_body
,
decorators
=
None
,
is_async_def
=
0
,
return_type_annotation
=
None
)
class
PropertyNode
(
StatNode
):
# Definition of a property in an extension type.
#
...
...
This diff is collapsed.
Click to expand it.
Cython/Compiler/Pipeline.py
View file @
70f6d6e5
...
...
@@ -141,7 +141,7 @@ def inject_utility_code_stage_factory(context):
def
create_pipeline
(
context
,
mode
,
exclude_classes
=
()):
assert
mode
in
(
'pyx'
,
'py'
,
'pxd'
)
from
.Visitor
import
PrintTree
from
.CypclassWrapper
import
CypclassWrapperInjection
,
CypclassPostDeclarationsVisitor
from
.CypclassWrapper
import
CypclassWrapperInjection
from
.ParseTreeTransforms
import
WithTransform
,
NormalizeTree
,
PostParse
,
PxdPostParse
from
.ParseTreeTransforms
import
ForwardDeclareTypes
,
InjectGilHandling
,
AnalyseDeclarationsTransform
from
.ParseTreeTransforms
import
AnalyseExpressionsTransform
,
FindInvalidUseOfFusedTypes
...
...
@@ -199,7 +199,6 @@ def create_pipeline(context, mode, exclude_classes=()):
ForwardDeclareTypes
(
context
),
InjectGilHandling
(),
AnalyseDeclarationsTransform
(
context
),
CypclassPostDeclarationsVisitor
(
context
),
AutoTestDictTransform
(
context
),
EmbedSignature
(
context
),
EarlyReplaceBuiltinCalls
(
context
),
## Necessary?
...
...
This diff is collapsed.
Click to expand it.
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