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
Gwenaël Samain
cython
Commits
f7d7598f
Commit
f7d7598f
authored
Mar 29, 2011
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
09d92f6f
27961df2
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
436 additions
and
131 deletions
+436
-131
Cython/CodeWriter.py
Cython/CodeWriter.py
+267
-79
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+0
-1
Cython/Debugger/Tests/test_libcython_in_gdb.py
Cython/Debugger/Tests/test_libcython_in_gdb.py
+26
-0
Cython/Debugger/Tests/test_libpython_in_gdb.py
Cython/Debugger/Tests/test_libpython_in_gdb.py
+1
-3
Cython/Debugger/libcython.py
Cython/Debugger/libcython.py
+84
-17
Cython/Debugger/libpython.py
Cython/Debugger/libpython.py
+58
-31
No files found.
Cython/CodeWriter.py
View file @
f7d7598f
...
...
@@ -26,12 +26,12 @@ class LinesResult(object):
self
.
put
(
s
)
self
.
newline
()
class
Code
Writer
(
TreeVisitor
):
class
Declaration
Writer
(
TreeVisitor
):
indent_string
=
u" "
def
__init__
(
self
,
result
=
None
):
super
(
Code
Writer
,
self
).
__init__
()
super
(
Declaration
Writer
,
self
).
__init__
()
if
result
is
None
:
result
=
LinesResult
()
self
.
result
=
result
...
...
@@ -41,6 +41,7 @@ class CodeWriter(TreeVisitor):
def
write
(
self
,
tree
):
self
.
visit
(
tree
)
return
self
.
result
def
indent
(
self
):
self
.
numindents
+=
1
...
...
@@ -54,6 +55,9 @@ class CodeWriter(TreeVisitor):
def
put
(
self
,
s
):
self
.
result
.
put
(
s
)
def
putline
(
self
,
s
):
self
.
result
.
putline
(
self
.
indent_string
*
self
.
numindents
+
s
)
def
endline
(
self
,
s
=
u""
):
self
.
result
.
putline
(
s
)
...
...
@@ -79,23 +83,45 @@ class CodeWriter(TreeVisitor):
def
visit_StatListNode
(
self
,
node
):
self
.
visitchildren
(
node
)
def
visit_FuncDefNode
(
self
,
node
):
self
.
startline
(
u"def %s("
%
node
.
name
)
self
.
comma_separated_list
(
node
.
args
)
self
.
endline
(
u"):"
)
def
visit_CDefExternNode
(
self
,
node
):
if
node
.
include_file
is
None
:
file
=
u'*'
else
:
file
=
u'"%s"'
%
node
.
include_file
self
.
putline
(
u"cdef extern from %s:"
%
file
)
self
.
indent
()
self
.
visit
(
node
.
body
)
self
.
dedent
()
def
visit_CArgDeclNode
(
self
,
node
):
if
node
.
base_type
.
name
is
not
None
:
self
.
visit
(
node
.
base_type
)
self
.
put
(
u" "
)
self
.
visit
(
node
.
declarator
)
if
node
.
default
is
not
None
:
self
.
put
(
u" = "
)
self
.
visit
(
node
.
default
)
def
visit_CPtrDeclaratorNode
(
self
,
node
):
self
.
put
(
'*'
)
self
.
visit
(
node
.
base
)
def
visit_CReferenceDeclaratorNode
(
self
,
node
):
self
.
put
(
'&'
)
self
.
visit
(
node
.
base
)
def
visit_CArrayDeclaratorNode
(
self
,
node
):
self
.
visit
(
node
.
base
)
self
.
put
(
u'['
)
if
node
.
dimension
is
not
None
:
self
.
visit
(
node
.
dimension
)
self
.
put
(
u']'
)
def
visit_CArrayDeclaratorNode
(
self
,
node
):
self
.
visit
(
node
.
base
)
self
.
put
(
u'['
)
if
node
.
dimension
is
not
None
:
self
.
visit
(
node
.
dimension
)
self
.
put
(
u']'
)
def
visit_CFuncDeclaratorNode
(
self
,
node
):
# TODO: except, gil, etc.
self
.
visit
(
node
.
base
)
self
.
put
(
u'('
)
self
.
comma_separated_list
(
node
.
args
)
self
.
endline
(
u')'
)
def
visit_CNameDeclaratorNode
(
self
,
node
):
self
.
put
(
node
.
name
)
...
...
@@ -108,22 +134,149 @@ class CodeWriter(TreeVisitor):
self
.
put
(
"short "
*
-
node
.
longness
)
elif
node
.
longness
>
0
:
self
.
put
(
"long "
*
node
.
longness
)
self
.
put
(
node
.
name
)
def
visit_CComplexBaseTypeNode
(
self
,
node
):
self
.
put
(
u'('
)
self
.
visit
(
node
.
base_type
)
self
.
visit
(
node
.
declarator
)
self
.
put
(
u')'
)
def
visit_CNestedBaseTypeNode
(
self
,
node
):
self
.
visit
(
node
.
base_type
)
self
.
put
(
u'.'
)
self
.
put
(
node
.
name
)
def
visit_SingleAssignmentNode
(
self
,
node
):
self
.
startline
()
self
.
visit
(
node
.
lhs
)
self
.
put
(
u" = "
)
self
.
visit
(
node
.
rhs
)
def
visit_TemplatedTypeNode
(
self
,
node
):
self
.
visit
(
node
.
base_type_node
)
self
.
put
(
u'['
)
self
.
comma_separated_list
(
node
.
positional_args
+
node
.
keyword_args
.
key_value_pairs
)
self
.
put
(
u']'
)
def
visit_CVarDefNode
(
self
,
node
):
self
.
startline
(
u"cdef "
)
self
.
visit
(
node
.
base_type
)
self
.
put
(
u" "
)
self
.
comma_separated_list
(
node
.
declarators
,
output_rhs
=
True
)
self
.
endline
()
def
visit_CascadedAssignmentNode
(
self
,
node
):
self
.
startline
()
for
lhs
in
node
.
lhs_list
:
self
.
visit
(
lhs
)
def
visit_container_node
(
self
,
node
,
decl
,
extras
,
attributes
):
# TODO: visibility
self
.
startline
(
decl
)
if
node
.
name
:
self
.
put
(
u' '
)
self
.
put
(
node
.
name
)
if
node
.
cname
is
not
None
:
self
.
put
(
u' "%s"'
%
node
.
cname
)
if
extras
:
self
.
put
(
extras
)
self
.
endline
(
':'
)
self
.
indent
()
if
not
attributes
:
self
.
putline
(
'pass'
)
else
:
for
attribute
in
attributes
:
self
.
visit
(
attribute
)
self
.
dedent
()
def
visit_CStructOrUnionDefNode
(
self
,
node
):
if
node
.
typedef_flag
:
decl
=
u'ctypedef '
else
:
decl
=
u'cdef '
if
node
.
visibility
==
'public'
:
decl
+=
u'public '
if
node
.
packed
:
decl
+=
u'packed '
decl
+=
node
.
kind
self
.
visit_container_node
(
node
,
decl
,
None
,
node
.
attributes
)
def
visit_CppClassNode
(
self
,
node
):
extras
=
""
if
node
.
templates
:
extras
=
u"[%s]"
%
", "
.
join
(
node
.
templates
)
if
node
.
base_classes
:
extras
+=
"(%s)"
%
", "
.
join
(
node
.
base_classes
)
self
.
visit_container_node
(
node
,
u"cdef cppclass"
,
extras
,
node
.
attributes
)
def
visit_CEnumDefNode
(
self
,
node
):
self
.
visit_container_node
(
node
,
u"cdef enum"
,
None
,
node
.
items
)
def
visit_CEnumDefItemNode
(
self
,
node
):
self
.
startline
(
node
.
name
)
if
node
.
cname
:
self
.
put
(
u' "%s"'
%
node
.
cname
)
if
node
.
value
:
self
.
put
(
u" = "
)
self
.
visit
(
node
.
rhs
)
self
.
visit
(
node
.
value
)
self
.
endline
()
def
visit_CClassDefNode
(
self
,
node
):
assert
not
node
.
module_name
if
node
.
decorators
:
for
decorator
in
node
.
decorators
:
self
.
visit
(
decorator
)
self
.
startline
(
u"cdef class "
)
self
.
put
(
node
.
class_name
)
if
node
.
base_class_name
:
self
.
put
(
u"("
)
if
node
.
base_class_module
:
self
.
put
(
node
.
base_class_module
)
self
.
put
(
u"."
)
self
.
put
(
node
.
base_class_name
)
self
.
put
(
u")"
)
self
.
endline
(
u":"
)
self
.
indent
()
self
.
visit
(
node
.
body
)
self
.
dedent
()
def
visit_CTypeDefNode
(
self
,
node
):
self
.
startline
(
u"ctypedef "
)
self
.
visit
(
node
.
base_type
)
self
.
put
(
u" "
)
self
.
visit
(
node
.
declarator
)
self
.
endline
()
def
visit_FuncDefNode
(
self
,
node
):
self
.
startline
(
u"def %s("
%
node
.
name
)
self
.
comma_separated_list
(
node
.
args
)
self
.
endline
(
u"):"
)
self
.
indent
()
self
.
visit
(
node
.
body
)
self
.
dedent
()
def
visit_CArgDeclNode
(
self
,
node
):
if
node
.
base_type
.
name
is
not
None
:
self
.
visit
(
node
.
base_type
)
self
.
put
(
u" "
)
self
.
visit
(
node
.
declarator
)
if
node
.
default
is
not
None
:
self
.
put
(
u" = "
)
self
.
visit
(
node
.
default
)
def
visit_CImportStatNode
(
self
,
node
):
self
.
startline
(
u"cimport "
)
self
.
put
(
node
.
module_name
)
if
node
.
as_name
:
self
.
put
(
u" as "
)
self
.
put
(
node
.
as_name
)
self
.
endline
()
def
visit_FromCImportStatNode
(
self
,
node
):
self
.
startline
(
u"from "
)
self
.
put
(
node
.
module_name
)
self
.
put
(
u" cimport "
)
first
=
True
for
pos
,
name
,
as_name
,
kind
in
node
.
imported_names
:
assert
kind
is
None
if
first
:
first
=
False
else
:
self
.
put
(
u", "
)
self
.
put
(
name
)
if
as_name
:
self
.
put
(
u" as "
)
self
.
put
(
as_name
)
self
.
endline
()
def
visit_NameNode
(
self
,
node
):
...
...
@@ -132,6 +285,31 @@ class CodeWriter(TreeVisitor):
def
visit_IntNode
(
self
,
node
):
self
.
put
(
node
.
value
)
def
visit_NoneNode
(
self
,
node
):
self
.
put
(
u"None"
)
def
visit_NotNode
(
self
,
node
):
self
.
put
(
u"(not "
)
self
.
visit
(
node
.
operand
)
self
.
put
(
u")"
)
def
visit_DecoratorNode
(
self
,
node
):
self
.
startline
(
"@"
)
self
.
visit
(
node
.
decorator
)
self
.
endline
()
def
visit_BinopNode
(
self
,
node
):
self
.
visit
(
node
.
operand1
)
self
.
put
(
u" %s "
%
node
.
operator
)
self
.
visit
(
node
.
operand2
)
def
visit_AttributeNode
(
self
,
node
):
self
.
visit
(
node
.
obj
)
self
.
put
(
u".%s"
%
node
.
attribute
)
def
visit_BoolNode
(
self
,
node
):
self
.
put
(
str
(
node
.
value
))
# FIXME: represent string nodes correctly
def
visit_StringNode
(
self
,
node
):
value
=
node
.
value
...
...
@@ -139,32 +317,27 @@ class CodeWriter(TreeVisitor):
value
=
value
.
encode
(
value
.
encoding
)
self
.
put
(
repr
(
value
))
def
visit_IfStatNode
(
self
,
node
):
# The IfClauseNode is handled directly without a seperate match
# for clariy.
self
.
startline
(
u"if "
)
self
.
visit
(
node
.
if_clauses
[
0
].
condition
)
self
.
endline
(
":"
)
self
.
indent
()
self
.
visit
(
node
.
if_clauses
[
0
].
body
)
self
.
dedent
()
for
clause
in
node
.
if_clauses
[
1
:]:
self
.
startline
(
"elif "
)
self
.
visit
(
clause
.
condition
)
self
.
endline
(
":"
)
self
.
indent
()
self
.
visit
(
clause
.
body
)
self
.
dedent
()
if
node
.
else_clause
is
not
None
:
self
.
line
(
"else:"
)
self
.
indent
()
self
.
visit
(
node
.
else_clause
)
self
.
dedent
()
def
visit_PassStatNode
(
self
,
node
):
self
.
startline
(
u"pass"
)
self
.
endline
()
class
CodeWriter
(
DeclarationWriter
):
def
visit_SingleAssignmentNode
(
self
,
node
):
self
.
startline
()
self
.
visit
(
node
.
lhs
)
self
.
put
(
u" = "
)
self
.
visit
(
node
.
rhs
)
self
.
endline
()
def
visit_CascadedAssignmentNode
(
self
,
node
):
self
.
startline
()
for
lhs
in
node
.
lhs_list
:
self
.
visit
(
lhs
)
self
.
put
(
u" = "
)
self
.
visit
(
node
.
rhs
)
self
.
endline
()
def
visit_PrintStatNode
(
self
,
node
):
self
.
startline
(
u"print "
)
self
.
comma_separated_list
(
node
.
arg_tuple
.
args
)
...
...
@@ -172,18 +345,6 @@ class CodeWriter(TreeVisitor):
self
.
put
(
u","
)
self
.
endline
()
def
visit_BinopNode
(
self
,
node
):
self
.
visit
(
node
.
operand1
)
self
.
put
(
u" %s "
%
node
.
operator
)
self
.
visit
(
node
.
operand2
)
def
visit_CVarDefNode
(
self
,
node
):
self
.
startline
(
u"cdef "
)
self
.
visit
(
node
.
base_type
)
self
.
put
(
u" "
)
self
.
comma_separated_list
(
node
.
declarators
,
output_rhs
=
True
)
self
.
endline
()
def
visit_ForInStatNode
(
self
,
node
):
self
.
startline
(
u"for "
)
self
.
visit
(
node
.
target
)
...
...
@@ -199,6 +360,28 @@ class CodeWriter(TreeVisitor):
self
.
visit
(
node
.
else_clause
)
self
.
dedent
()
def
visit_IfStatNode
(
self
,
node
):
# The IfClauseNode is handled directly without a seperate match
# for clariy.
self
.
startline
(
u"if "
)
self
.
visit
(
node
.
if_clauses
[
0
].
condition
)
self
.
endline
(
":"
)
self
.
indent
()
self
.
visit
(
node
.
if_clauses
[
0
].
body
)
self
.
dedent
()
for
clause
in
node
.
if_clauses
[
1
:]:
self
.
startline
(
"elif "
)
self
.
visit
(
clause
.
condition
)
self
.
endline
(
":"
)
self
.
indent
()
self
.
visit
(
clause
.
body
)
self
.
dedent
()
if
node
.
else_clause
is
not
None
:
self
.
line
(
"else:"
)
self
.
indent
()
self
.
visit
(
node
.
else_clause
)
self
.
dedent
()
def
visit_SequenceNode
(
self
,
node
):
self
.
comma_separated_list
(
node
.
args
)
# Might need to discover whether we need () around tuples...hmm...
...
...
@@ -244,13 +427,6 @@ class CodeWriter(TreeVisitor):
self
.
visit
(
node
.
body
)
self
.
dedent
()
def
visit_AttributeNode
(
self
,
node
):
self
.
visit
(
node
.
obj
)
self
.
put
(
u".%s"
%
node
.
attribute
)
def
visit_BoolNode
(
self
,
node
):
self
.
put
(
str
(
node
.
value
))
def
visit_TryFinallyStatNode
(
self
,
node
):
self
.
line
(
u"try:"
)
self
.
indent
()
...
...
@@ -289,25 +465,12 @@ class CodeWriter(TreeVisitor):
self
.
visit
(
node
.
value
)
self
.
endline
()
def
visit_DecoratorNode
(
self
,
node
):
self
.
startline
(
"@"
)
self
.
visit
(
node
.
decorator
)
self
.
endline
()
def
visit_ReraiseStatNode
(
self
,
node
):
self
.
line
(
"raise"
)
def
visit_NoneNode
(
self
,
node
):
self
.
put
(
u"None"
)
def
visit_ImportNode
(
self
,
node
):
self
.
put
(
u"(import %s)"
%
node
.
module_name
.
value
)
def
visit_NotNode
(
self
,
node
):
self
.
put
(
u"(not "
)
self
.
visit
(
node
.
operand
)
self
.
put
(
u")"
)
def
visit_TempsBlockNode
(
self
,
node
):
"""
Temporaries are output like $1_1', where the first number is
...
...
@@ -323,3 +486,28 @@ class CodeWriter(TreeVisitor):
def
visit_TempRefNode
(
self
,
node
):
self
.
put
(
self
.
tempnames
[
node
.
handle
])
class
PxdWriter
(
DeclarationWriter
):
def
__call__
(
self
,
node
):
print
u'
\
n
'
.
join
(
self
.
write
(
node
).
lines
)
return
node
def
visit_CFuncDefNode
(
self
,
node
):
if
'inline'
in
node
.
modifiers
:
return
if
node
.
overridable
:
self
.
startline
(
u'cpdef '
)
else
:
self
.
startline
(
u'cdef '
)
if
node
.
visibility
!=
'private'
:
self
.
put
(
node
.
visibility
)
self
.
put
(
u' '
)
if
node
.
api
:
self
.
put
(
u'api '
)
self
.
visit
(
node
.
declarator
)
def
visit_StatNode
(
self
,
node
):
pass
\ No newline at end of file
Cython/Compiler/ParseTreeTransforms.py
View file @
f7d7598f
...
...
@@ -64,7 +64,6 @@ class SkipDeclarations(object):
def
visit_CStructOrUnionDefNode
(
self
,
node
):
return
node
class
NormalizeTree
(
CythonTransform
):
"""
This transform fixes up a few things after parsing
...
...
Cython/Debugger/Tests/test_libcython_in_gdb.py
View file @
f7d7598f
...
...
@@ -378,6 +378,32 @@ class TestExec(DebugTestCase):
gdb
.
execute
(
'cy exec some_random_var = 14'
)
self
.
assertEqual
(
'14'
,
self
.
eval_command
(
'some_random_var'
))
class
CySet
(
DebugTestCase
):
def
test_cyset
(
self
):
self
.
break_and_run
(
'os.path.join("foo", "bar")'
)
gdb
.
execute
(
'cy set a = $cy_eval("{None: []}")'
)
stringvalue
=
self
.
read_var
(
"a"
,
cast_to
=
str
)
self
.
assertEqual
(
stringvalue
,
"{None: []}"
)
class
TestCyEval
(
DebugTestCase
):
"Test the $cy_eval() gdb function."
def
test_cy_eval
(
self
):
# This function leaks a few objects in the GDB python process. This
# is no biggie
self
.
break_and_run
(
'os.path.join("foo", "bar")'
)
result
=
gdb
.
execute
(
'print $cy_eval("None")'
,
to_string
=
True
)
assert
re
.
match
(
r'\
$
\d+ = None\n'
,
result
),
result
result
=
gdb
.
execute
(
'print $cy_eval("[a]")'
,
to_string
=
True
)
assert
re
.
match
(
r'\
$
\d+ = \
[
0\
]
', result), result
class TestClosure(DebugTestCase):
def break_and_run_func(self, funcname):
...
...
Cython/Debugger/Tests/test_libpython_in_gdb.py
View file @
f7d7598f
...
...
@@ -112,6 +112,4 @@ class TestPrettyPrinters(test_libcython_in_gdb.DebugTestCase):
def
test_frame_type
(
self
):
frame
=
self
.
pyobject_fromcode
(
'PyEval_GetFrame()'
)
self
.
assertEqual
(
type
(
frame
),
libpython
.
PyFrameObjectPtr
)
self
.
assertEqual
(
type
(
frame
),
libpython
.
PyFrameObjectPtr
)
\ No newline at end of file
Cython/Debugger/libcython.py
View file @
f7d7598f
...
...
@@ -592,6 +592,7 @@ class CyCy(CythonCommand):
cy bt / cy backtrace
cy list
cy print
cy set
cy locals
cy globals
cy exec
...
...
@@ -607,6 +608,7 @@ class CyCy(CythonCommand):
completer_class
,
prefix
=
True
)
commands
=
dict
(
# GDB commands
import_
=
CyImport
.
register
(),
break_
=
CyBreak
.
register
(),
step
=
CyStep
.
register
(),
...
...
@@ -624,9 +626,13 @@ class CyCy(CythonCommand):
globals
=
CyGlobals
.
register
(),
exec_
=
libpython
.
FixGdbCommand
(
'cy exec'
,
'-cy-exec'
),
_exec
=
CyExec
.
register
(),
set
=
CySet
.
register
(),
# GDB functions
cy_cname
=
CyCName
(
'cy_cname'
),
cy_cvalue
=
CyCValue
(
'cy_cvalue'
),
cy_lineno
=
CyLine
(
'cy_lineno'
),
cy_eval
=
CyEval
(
'cy_eval'
),
)
for
command_name
,
command
in
commands
.
iteritems
():
...
...
@@ -1169,15 +1175,14 @@ class CyGlobals(CyLocals):
max_name_length
,
' '
)
class
CyExec
(
CythonCommand
,
libpython
.
PyExec
):
class
EvaluateOrExecuteCodeMixin
(
object
):
"""
Execute Python code in the nearest Python or Cython frame.
Evaluate or execute Python code in a Cython or Python frame. The 'evalcode'
method evaluations Python code, prints a traceback if an exception went
uncaught, and returns any return value as a gdb.Value (NULL on exception).
"""
name
=
'-cy-exec'
command_class
=
gdb
.
COMMAND_STACK
completer_class
=
gdb
.
COMPLETE_NONE
def
_fill_locals_dict
(
self
,
executor
,
local_dict_pointer
):
"Fill a remotely allocated dict with values from the Cython C stack"
cython_func
=
self
.
get_cython_function
()
...
...
@@ -1208,28 +1213,22 @@ class CyExec(CythonCommand, libpython.PyExec):
raise
gdb
.
GdbError
(
"Unable to execute Python code."
)
finally
:
# PyDict_SetItem doesn't steal our reference
executor
.
decref
(
pystringp
)
executor
.
x
decref
(
pystringp
)
def
_find_first_cython_or_python_frame
(
self
):
frame
=
gdb
.
selected_frame
()
while
frame
:
if
(
self
.
is_cython_function
(
frame
)
or
self
.
is_python_function
(
frame
)):
frame
.
select
()
return
frame
frame
=
frame
.
older
()
raise
gdb
.
GdbError
(
"There is no Cython or Python frame on the stack."
)
def
invoke
(
self
,
expr
,
from_tty
):
frame
=
self
.
_find_first_cython_or_python_frame
()
if
self
.
is_python_function
(
frame
):
libpython
.
py_exec
.
invoke
(
expr
,
from_tty
)
return
expr
,
input_type
=
self
.
readcode
(
expr
)
executor
=
libpython
.
PythonCodeExecutor
()
def
_evalcode_cython
(
self
,
executor
,
code
,
input_type
):
with
libpython
.
FetchAndRestoreError
():
# get the dict of Cython globals and construct a dict in the
# inferior with Cython locals
...
...
@@ -1240,9 +1239,65 @@ class CyExec(CythonCommand, libpython.PyExec):
try
:
self
.
_fill_locals_dict
(
executor
,
libpython
.
pointervalue
(
local_dict
))
executor
.
evalcode
(
expr
,
input_type
,
global_dict
,
local_dict
)
result
=
executor
.
evalcode
(
code
,
input_type
,
global_dict
,
local_dict
)
finally
:
executor
.
decref
(
libpython
.
pointervalue
(
local_dict
))
executor
.
xdecref
(
libpython
.
pointervalue
(
local_dict
))
return
result
def
evalcode
(
self
,
code
,
input_type
):
"""
Evaluate `code` in a Python or Cython stack frame using the given
`input_type`.
"""
frame
=
self
.
_find_first_cython_or_python_frame
()
executor
=
libpython
.
PythonCodeExecutor
()
if
self
.
is_python_function
(
frame
):
return
libpython
.
_evalcode_python
(
executor
,
code
,
input_type
)
return
self
.
_evalcode_cython
(
executor
,
code
,
input_type
)
class
CyExec
(
CythonCommand
,
libpython
.
PyExec
,
EvaluateOrExecuteCodeMixin
):
"""
Execute Python code in the nearest Python or Cython frame.
"""
name
=
'-cy-exec'
command_class
=
gdb
.
COMMAND_STACK
completer_class
=
gdb
.
COMPLETE_NONE
def
invoke
(
self
,
expr
,
from_tty
):
expr
,
input_type
=
self
.
readcode
(
expr
)
executor
=
libpython
.
PythonCodeExecutor
()
executor
.
xdecref
(
self
.
evalcode
(
expr
,
executor
.
Py_single_input
))
class
CySet
(
CythonCommand
):
"""
Set a Cython variable to a certain value
cy set my_cython_c_variable = 10
cy set my_cython_py_variable = $cy_eval("{'doner': 'kebab'}")
This is equivalent to
set $cy_value("my_cython_variable") = 10
"""
name
=
'cy set'
command_class
=
gdb
.
COMMAND_DATA
completer_class
=
gdb
.
COMPLETE_NONE
@
require_cython_frame
def
invoke
(
self
,
expr
,
from_tty
):
name_and_expr
=
expr
.
split
(
'='
,
1
)
if
len
(
name_and_expr
)
!=
2
:
raise
gdb
.
GdbError
(
"Invalid expression. Use 'cy set var = expr'."
)
varname
,
expr
=
name_and_expr
cname
=
self
.
cy
.
cy_cname
.
invoke
(
varname
.
strip
())
gdb
.
execute
(
"set %s = %s"
%
(
cname
,
expr
))
# Functions
...
...
@@ -1312,6 +1367,18 @@ class CyLine(gdb.Function, CythonBase):
def
invoke
(
self
):
return
self
.
get_cython_lineno
()
class
CyEval
(
gdb
.
Function
,
CythonBase
,
EvaluateOrExecuteCodeMixin
):
"""
Evaluate Python code in the nearest Python or Cython frame and return
"""
@
gdb_function_value_to_unicode
def
invoke
(
self
,
python_expression
):
input_type
=
libpython
.
PythonCodeExecutor
.
Py_eval_input
return
self
.
evalcode
(
python_expression
,
input_type
)
cython_info
=
CythonInfo
()
cy
=
CyCy
.
register
()
cython_info
.
cy
=
cy
...
...
Cython/Debugger/libpython.py
View file @
f7d7598f
...
...
@@ -1949,26 +1949,40 @@ class ExecutionControlCommandBase(gdb.Command):
gdb.execute("
delete
%
s
" % bp)
def filter_output(self, result):
output = []
match_finish = re.search(r'^Value returned is
\
$
\
d+ = (.*)', result,
re.MULTILINE)
if match_finish:
output.append('Value returned: %s' % match_finish.group(1))
reflags = re.MULTILINE
regexes = [
output_on_halt = [
(r'^Program received signal .*', reflags|re.DOTALL),
(r'.*[Ww]arning.*', 0),
(r'^Program exited .*', reflags),
]
for regex, flags in regexes:
match = re.search(regex, result, flags)
if match:
output.append(match.group(0))
output_always = [
# output when halting on a watchpoint
(r'^(Old|New) value = .*', reflags),
# output from the 'display' command
(r'^
\
d+:
\
w+ = .*', reflags),
]
def filter_output(regexes):
output = []
for regex, flags in regexes:
for match in re.finditer(regex, result, flags):
output.append(match.group(0))
return '
\
n
'.join(output)
# Filter the return value output of the 'finish' command
match_finish = re.search(r'^Value returned is
\
$
\
d+ = (.*)', result,
re.MULTILINE)
if match_finish:
finish_output = 'Value returned: %s
\
n
' % match_finish.group(1)
else:
finish_output = ''
return (filter_output(output_on_halt),
finish_output + filter_output(output_always))
return '
\
n
'.join(output)
def stopped(self):
return get_selected_inferior().pid == 0
...
...
@@ -1979,17 +1993,23 @@ class ExecutionControlCommandBase(gdb.Command):
of source code or the result of the last executed gdb command (passed
in as the `result` argument).
"""
result
= self.filter_output(result)
output_on_halt, output_always
= self.filter_output(result)
if self.stopped():
print result.strip()
print output_always
print output_on_halt
else:
frame = gdb.selected_frame()
source_line = self.lang_info.get_source_line(frame)
if self.lang_info.is_relevant_function(frame):
raised_exception = self.lang_info.exc_info(frame)
if raised_exception:
print raised_exception
print self.lang_info.get_source_line(frame) or result
if source_line:
if output_always.rstrip():
print output_always.rstrip()
print source_line
else:
print result
...
...
@@ -2190,12 +2210,12 @@ class PythonInfo(LanguageInfo):
try:
tstate = frame.read_var('
tstate
').dereference()
if gdb.parse_and_eval('
tstate
->
frame
==
f'):
# tstate local variable initialized
# tstate local variable initialized
, check for an exception
inf_type = tstate['
curexc_type
']
inf_value = tstate['
curexc_value
']
if inf_type:
return '
An
exception
was
raised
:
%
s
(
%
s
)
' % (inf_type,
inf_value)
return '
An
exception
was
raised
:
%
s
' % (inf_value,)
except (ValueError, RuntimeError), e:
# Could not read the variable tstate or it'
s
memory
,
it
's ok
pass
...
...
@@ -2342,7 +2362,7 @@ class PythonCodeExecutor(object):
"Increment the reference count of a Python object in the inferior."
gdb
.
parse_and_eval
(
'Py_IncRef((PyObject *) %d)'
%
pointer
)
def
decref
(
self
,
pointer
):
def
x
decref
(
self
,
pointer
):
"Decrement the reference count of a Python object in the inferior."
# Py_DecRef is like Py_XDECREF, but a function. So we don't have
# to check for NULL. This should also decref all our allocated
...
...
@@ -2382,10 +2402,11 @@ class PythonCodeExecutor(object):
with
FetchAndRestoreError
():
try
:
self
.
decref
(
gdb
.
parse_and_eval
(
code
)
)
pyobject_return_value
=
gdb
.
parse_and_eval
(
code
)
finally
:
self
.
free
(
pointer
)
return
pyobject_return_value
class
FetchAndRestoreError
(
PythonCodeExecutor
):
"""
...
...
@@ -2462,6 +2483,20 @@ class FixGdbCommand(gdb.Command):
self
.
fix_gdb
()
def
_evalcode_python
(
executor
,
code
,
input_type
):
"""
Execute Python code in the most recent stack frame.
"""
global_dict
=
gdb
.
parse_and_eval
(
'PyEval_GetGlobals()'
)
local_dict
=
gdb
.
parse_and_eval
(
'PyEval_GetLocals()'
)
if
(
pointervalue
(
global_dict
)
==
0
or
pointervalue
(
local_dict
)
==
0
):
raise
gdb
.
GdbError
(
"Unable to find the locals or globals of the "
"most recent Python function (relative to the "
"selected frame)."
)
return
executor
.
evalcode
(
code
,
input_type
,
global_dict
,
local_dict
)
class
PyExec
(
gdb
.
Command
):
def
readcode
(
self
,
expr
):
...
...
@@ -2484,17 +2519,9 @@ class PyExec(gdb.Command):
def
invoke
(
self
,
expr
,
from_tty
):
expr
,
input_type
=
self
.
readcode
(
expr
)
executor
=
PythonCodeExecutor
()
global_dict
=
gdb
.
parse_and_eval
(
'PyEval_GetGlobals()'
)
local_dict
=
gdb
.
parse_and_eval
(
'PyEval_GetLocals()'
)
if
pointervalue
(
global_dict
)
==
0
or
pointervalue
(
local_dict
)
==
0
:
raise
gdb
.
GdbError
(
"Unable to find the locals or globals of the "
"most recent Python function (relative to the "
"selected frame)."
)
executor
.
evalcode
(
expr
,
input_type
,
global_dict
,
local_dict
)
executor
.
xdecref
(
_evalcode_python
(
executor
,
input_type
,
global_dict
,
local_dict
))
gdb
.
execute
(
'set breakpoint pending on'
)
...
...
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