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
d2e2abb1
Commit
d2e2abb1
authored
Jul 28, 2020
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve generation of cypclass method wrappers
parent
a2548922
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
76 additions
and
38 deletions
+76
-38
Cython/Compiler/CypclassWrapper.py
Cython/Compiler/CypclassWrapper.py
+70
-38
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+6
-0
No files found.
Cython/Compiler/CypclassWrapper.py
View file @
d2e2abb1
...
@@ -270,13 +270,31 @@ def NAME(self, ARGDECLS):
...
@@ -270,13 +270,31 @@ def NAME(self, ARGDECLS):
return
wrapper
return
wrapper
def
insert_cypclass_method_wrappers
(
self
,
node
,
cclass_name
,
stats
):
def
insert_cypclass_method_wrappers
(
self
,
node
,
cclass_name
,
stats
):
for
attr
in
node
.
attributes
:
for
attr
in
node
.
scope
.
entries
.
values
():
if
isinstance
(
attr
,
Nodes
.
CFuncDefNode
):
if
attr
.
is_cfunction
:
alternatives
=
attr
.
all_alternatives
()
# > consider the alternatives that are actually defined in this wrapped cypclass
local_alternatives
=
[
e
for
e
in
alternatives
if
e
.
mro_index
==
0
]
if
len
(
local_alternatives
)
==
0
:
# all alternatives are inherited, skip this method
continue
if
len
(
alternatives
)
>
1
:
py_args_alternatives
=
[
e
for
e
in
local_alternatives
if
all
(
arg
.
type
.
is_pyobject
for
arg
in
e
.
type
.
args
)]
if
len
(
py_args_alternatives
)
==
1
:
# if there is a single locally defined method with all-python arguments, use that one
attr
=
py_args_alternatives
[
0
]
else
:
# else skip overloaded method for now
continue
py_method_wrapper
=
self
.
synthesize_cypclass_method_wrapper
(
node
,
cclass_name
,
attr
)
py_method_wrapper
=
self
.
synthesize_cypclass_method_wrapper
(
node
,
cclass_name
,
attr
)
if
py_method_wrapper
:
if
py_method_wrapper
:
stats
.
append
(
py_method_wrapper
)
stats
.
append
(
py_method_wrapper
)
for
attr
in
node
.
scope
.
var_entries
:
if
not
(
attr
.
is_cfunction
or
attr
.
is_type
)
:
elif
not
attr
.
is_type
:
property
=
self
.
synthesize_property
(
attr
,
node
.
entry
)
property
=
self
.
synthesize_property
(
attr
,
node
.
entry
)
if
property
:
if
property
:
stats
.
append
(
property
)
stats
.
append
(
property
)
...
@@ -300,66 +318,80 @@ def NAME(self, ARGDECLS):
...
@@ -300,66 +318,80 @@ def NAME(self, ARGDECLS):
property
.
doc
=
attr_entry
.
doc
property
.
doc
=
attr_entry
.
doc
return
property
return
property
def
synthesize_cypclass_method_wrapper
(
self
,
node
,
cclass_name
,
cfunc_method
):
def
synthesize_cypclass_method_wrapper
(
self
,
node
,
cclass_name
,
method_entry
):
if
cfunc_method
.
is_static_method
:
if
method_entry
.
type
.
is_static_method
:
return
# for now skip static methods
return
# for now skip static methods
if
cfunc_method
.
entry
.
name
in
(
"<del>"
,
):
if
method_entry
.
name
in
(
"<del>"
,
"<alloc>"
,
"__new__"
,
"<constructor>"
):
# skip special methods that should not be wrapped
# skip special methods that should not be wrapped
return
return
alternatives
=
cfunc_method
.
entry
.
all_alternatives
()
method_type
=
method_entry
.
type
# > consider only the alternatives that are actually defined in this wrapped cypclass
alternatives
=
list
(
filter
(
lambda
e
:
e
.
mro_index
==
0
,
alternatives
))
if
len
(
alternatives
)
>
1
:
if
method_type
.
optional_arg_count
:
py_args_alternatives
=
[
e
for
e
in
alternatives
if
all
(
arg
.
type
.
is_pyobject
for
arg
in
e
.
type
.
args
)]
return
# for now skip method with optional arguments
if
len
(
py_args_alternatives
)
==
1
and
cfunc_method
.
entry
is
py_args_alternatives
[
0
]:
pass
else
:
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
return_type
=
method_type
.
return_type
cfunc_return_type
=
cfunc_type
.
return_type
# we pass the global scope as argument, should not affect the result (?)
# we pass the global scope as argument, should not affect the result (?)
if
not
cfunc_
return_type
.
can_coerce_to_pyobject
(
self
.
module_scope
):
if
not
return_type
.
can_coerce_to_pyobject
(
self
.
module_scope
):
return
# skip c methods with Python-incompatible return types
return
# skip c methods with Python-incompatible return types
for
argtype
in
cfunc
_type
.
args
:
for
argtype
in
method
_type
.
args
:
if
not
argtype
.
type
.
can_coerce_from_pyobject
(
self
.
module_scope
):
if
not
argtype
.
type
.
can_coerce_from_pyobject
(
self
.
module_scope
):
return
# skip c methods with Python-incompatible argument types
return
# skip c methods with Python-incompatible argument types
# > name of the wrapping method: same name as in the original code
# > name of the wrapping method: same name as in the original code
cfunc_name
=
cfunc_declarator
.
base
.
name
method_name
=
method_entry
.
original_name
py_name
=
cfunc_name
if
method_name
is
None
:
return
# skip methods that don't have an original name
py_name
=
method_name
# > all arguments of the wrapper method declaration
# > all arguments of the wrapper method declaration
py_args_decls
=
[]
py_args_decls
=
[]
for
arg
in
cfunc_declarator
.
args
:
for
arg
in
method_type
.
args
:
py_args_decls
.
append
(
arg
.
clone_node
())
arg_base_type
=
Nodes
.
CSimpleBaseTypeNode
(
method_entry
.
pos
,
name
=
None
,
module_path
=
[],
is_basic_c_type
=
0
,
signed
=
0
,
complex
=
0
,
longness
=
0
,
is_self_arg
=
0
,
templates
=
None
)
arg_declarator
=
Nodes
.
CNameDeclaratorNode
(
method_entry
.
pos
,
name
=
arg
.
name
,
cname
=
None
)
arg_decl
=
Nodes
.
CArgDeclNode
(
method_entry
.
pos
,
base_type
=
arg_base_type
,
declarator
=
arg_declarator
,
not_none
=
0
,
or_none
=
0
,
default
=
None
,
annotation
=
None
,
kw_only
=
0
)
py_args_decls
.
append
(
arg_decl
)
# > same docstring
# > same docstring
py_doc
=
cfunc_method
.
doc
py_doc
=
method_entry
.
doc
# > names of the arguments passed when calling the underlying method; self not included
# > 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
]
arg_objs
=
[
ExprNodes
.
NameNode
(
arg
.
pos
,
name
=
arg
.
name
)
for
arg
in
method_type
.
args
]
# > access the underlying attribute
# > access the underlying attribute
underlying_type
=
node
.
entry
.
type
underlying_type
=
node
.
entry
.
type
# > select the appropriate template
# > select the appropriate template
need_return
=
not
cfunc_
return_type
.
is_void
need_return
=
not
return_type
.
is_void
if
node
.
lock_mode
==
'checklock'
:
if
node
.
lock_mode
==
'checklock'
:
need_wlock
=
not
cfunc
_type
.
is_const_method
need_wlock
=
not
method
_type
.
is_const_method
if
need_wlock
:
if
need_wlock
:
template
=
self
.
wlocked_method
if
need_return
else
self
.
wlocked_method_no_return
template
=
self
.
wlocked_method
if
need_return
else
self
.
wlocked_method_no_return
else
:
else
:
...
@@ -372,10 +404,10 @@ def NAME(self, ARGDECLS):
...
@@ -372,10 +404,10 @@ def NAME(self, ARGDECLS):
# > instanciate the wrapper from the template
# > instanciate the wrapper from the template
method_wrapper
=
template
.
substitute
({
method_wrapper
=
template
.
substitute
({
"NAME"
:
cfunc
_name
,
"NAME"
:
method
_name
,
"ARGDECLS"
:
py_args_decls
,
"ARGDECLS"
:
py_args_decls
,
"TYPE"
:
underlying_type
,
"TYPE"
:
underlying_type
,
"OBJ"
:
ExprNodes
.
NameNode
(
cfunc_method
.
pos
,
name
=
underlying_name
),
"OBJ"
:
ExprNodes
.
NameNode
(
method_entry
.
pos
,
name
=
underlying_name
),
"ARGS"
:
arg_objs
"ARGS"
:
arg_objs
}).
stats
[
0
]
}).
stats
[
0
]
method_wrapper
.
doc
=
py_doc
method_wrapper
.
doc
=
py_doc
...
...
Cython/Compiler/Symtab.py
View file @
d2e2abb1
...
@@ -178,6 +178,8 @@ class Entry(object):
...
@@ -178,6 +178,8 @@ class Entry(object):
# overrides, if this entry represents a cypclass method
# overrides, if this entry represents a cypclass method
#
#
# static_cname string The cname of a static method in a cypclass
# static_cname string The cname of a static method in a cypclass
#
# original_name string The original name of a cpp or cypclass method
# TODO: utility_code and utility_code_definition serves the same purpose...
# TODO: utility_code and utility_code_definition serves the same purpose...
...
@@ -257,6 +259,7 @@ class Entry(object):
...
@@ -257,6 +259,7 @@ class Entry(object):
mro_index
=
0
mro_index
=
0
from_type
=
None
from_type
=
None
static_cname
=
None
static_cname
=
None
original_name
=
None
def
__init__
(
self
,
name
,
cname
,
type
,
pos
=
None
,
init
=
None
):
def
__init__
(
self
,
name
,
cname
,
type
,
pos
=
None
,
init
=
None
):
self
.
name
=
name
self
.
name
=
name
...
@@ -3031,6 +3034,8 @@ class CppClassScope(Scope):
...
@@ -3031,6 +3034,8 @@ class CppClassScope(Scope):
entry
=
self
.
declare_var
(
name
,
type
,
pos
,
entry
=
self
.
declare_var
(
name
,
type
,
pos
,
defining
=
defining
,
defining
=
defining
,
cname
=
cname
,
visibility
=
visibility
)
cname
=
cname
,
visibility
=
visibility
)
entry
.
original_name
=
original_name
if
reify
:
if
reify
:
self
.
reify_method
(
entry
)
self
.
reify_method
(
entry
)
#if prev_entry and not defining:
#if prev_entry and not defining:
...
@@ -3140,6 +3145,7 @@ class CppClassScope(Scope):
...
@@ -3140,6 +3145,7 @@ class CppClassScope(Scope):
if
entry
.
is_cfunction
:
if
entry
.
is_cfunction
:
entry
.
func_cname
=
base_entry
.
func_cname
entry
.
func_cname
=
base_entry
.
func_cname
entry
.
static_cname
=
base_entry
.
static_cname
entry
.
static_cname
=
base_entry
.
static_cname
entry
.
original_name
=
base_entry
.
original_name
for
base_entry
in
base_scope
.
type_entries
:
for
base_entry
in
base_scope
.
type_entries
:
if
base_entry
.
name
not
in
base_templates
:
if
base_entry
.
name
not
in
base_templates
:
...
...
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