diff --git a/src/Sindarin-Tests/SindarinDebuggerTest.class.st b/src/Sindarin-Tests/SindarinDebuggerTest.class.st index 0774bd5..07adb04 100644 --- a/src/Sindarin-Tests/SindarinDebuggerTest.class.st +++ b/src/Sindarin-Tests/SindarinDebuggerTest.class.st @@ -2011,6 +2011,21 @@ SindarinDebuggerTest >> testStepUntil [ self assert: i equals: 12 ] +{ #category : 'tests' } +SindarinDebuggerTest >> testStepUntilOverAnEnsureBlock [ + | i sindarin startingContext | + i := 20. + sindarin := SindarinDebugger + debug: [[ 5 timesRepeat:[i := i + 1]] ensure: [i := 42] ]. + startingContext := sindarin context. + sindarin stepUntil: [ i = 23 ]. + self assert: i equals: 23. + self should: [sindarin stepUntil: [ i = 30 ]] raise: DebuggedExecutionIsFinished. + self assert: i equals: 42. + "self assert: sindarin context identicalTo: startingContext " + +] + { #category : 'tests' } SindarinDebuggerTest >> testSteppingAnExecutionSignalingExceptions [ | scdbg | diff --git a/src/Sindarin/DebuggedExecutionException.class.st b/src/Sindarin/DebuggedExecutionException.class.st deleted file mode 100644 index 2549680..0000000 --- a/src/Sindarin/DebuggedExecutionException.class.st +++ /dev/null @@ -1,12 +0,0 @@ -Class { - #name : 'DebuggedExecutionException', - #superclass : 'Error', - #category : 'Sindarin-Exceptions', - #package : 'Sindarin', - #tag : 'Exceptions' -} - -{ #category : 'testing' } -DebuggedExecutionException >> isExceptionSignalledForDebuggedExecution [ - ^ true -] diff --git a/src/Sindarin/DebuggedExecutionIsFinished.class.st b/src/Sindarin/DebuggedExecutionIsFinished.class.st index b652f67..4cccddd 100644 --- a/src/Sindarin/DebuggedExecutionIsFinished.class.st +++ b/src/Sindarin/DebuggedExecutionIsFinished.class.st @@ -1,6 +1,9 @@ +" +I am raised when an execution debugged by Sindarin has finished. +" Class { #name : 'DebuggedExecutionIsFinished', - #superclass : 'DebuggedExecutionException', + #superclass : 'Error', #category : 'Sindarin-Exceptions', #package : 'Sindarin', #tag : 'Exceptions' diff --git a/src/Sindarin/Object.extension.st b/src/Sindarin/Object.extension.st deleted file mode 100644 index d0b1b50..0000000 --- a/src/Sindarin/Object.extension.st +++ /dev/null @@ -1,6 +0,0 @@ -Extension { #name : 'Object' } - -{ #category : '*Sindarin' } -Object >> isExceptionSignalledForDebuggedExecution [ - ^ false -] diff --git a/src/Sindarin/RBBlockDefinitionSearchingVisitor.class.st b/src/Sindarin/RBBlockDefinitionSearchingVisitor.class.st index 1f50da8..ae9ea12 100644 --- a/src/Sindarin/RBBlockDefinitionSearchingVisitor.class.st +++ b/src/Sindarin/RBBlockDefinitionSearchingVisitor.class.st @@ -1,3 +1,6 @@ +" +I visit an AST to find a particular block passed as parameter. +" Class { #name : 'RBBlockDefinitionSearchingVisitor', #superclass : 'OCProgramNodeVisitor', @@ -5,9 +8,9 @@ Class { 'blockToSearch', 'isBlockFound' ], - #category : 'Sindarin-Base', + #category : 'Sindarin-Core', #package : 'Sindarin', - #tag : 'Base' + #tag : 'Core' } { #category : 'instance creation' } diff --git a/src/Sindarin/SindarinDebugSession.class.st b/src/Sindarin/SindarinDebugSession.class.st index 15851d9..8d085fd 100644 --- a/src/Sindarin/SindarinDebugSession.class.st +++ b/src/Sindarin/SindarinDebugSession.class.st @@ -25,19 +25,30 @@ SindarinDebugSession class >> newWithName: aString forProcess: aProcess [ asSindarinDebugSession ] -{ #category : 'initialization' } -SindarinDebugSession >> activateEventTriggering [ - triggerEventOn := true. - self flag: 'Why not refreshing?'. - "self refreshAttachedDebugger." -] - { #category : 'converting' } SindarinDebugSession >> asSindarinDebugSession [ ^ self ] +{ #category : 'api - debug session' } +SindarinDebugSession >> basicStepInto: aContext [ + + ^ self debugSession stepInto: aContext +] + +{ #category : 'api - debug session' } +SindarinDebugSession >> basicStepOver: aContext [ + + ^ self debugSession stepOver: aContext +] + +{ #category : 'api - debug session' } +SindarinDebugSession >> basicStepThrough: aContext [ + + ^ self debugSession stepThrough: aContext +] + { #category : 'accessing' } SindarinDebugSession >> canBeTerminated [ @@ -93,22 +104,25 @@ SindarinDebugSession >> resumeAndClear [ { #category : 'debugging actions' } SindarinDebugSession >> stepInto: aContext [ - "Should not step more a process that is terminating, otherwise the image will get locked." - self flag: 'Why the image gets locked? Please investigate.'. + "Should not step more a process that is terminating, otherwise the image will get locked. + The image freeze is due to the stepping of the ensure block in doTerminationFromYourself that unwind the terminating context to nil and executes a jump. + The ensure executes the (fake) primitive 198 which actually freezes (see issue https://github.com/pharo-spec/ScriptableDebugger/issues/105), and prevents the jump to execute which in turn provokes other freezes when trying to close opened debugger on that partially ended process." self debugSession interruptedProcess isTerminating ifTrue: [ SteppingATerminatingProcess signal ]. - ^ self debugSession stepInto: aContext + ^ self basicStepInto: aContext ] { #category : 'debugging actions' } SindarinDebugSession >> stepOver: aContext [ - "Should not step more a process that is terminating, otherwise the image will get locked." - self flag: 'Why the image gets locked? Please investigate.'. + "Should not step more a process that is terminating, otherwise the image will get locked. + The image freeze is due to the stepping of the ensure block in doTerminationFromYourself that unwind the terminating context to nil and executes a jump. + The ensure executes the (fake) primitive 198 which actually freezes (see issue https://github.com/pharo-spec/ScriptableDebugger/issues/105), and prevents the jump to execute which in turn provokes other freezes when trying to close opened debugger on that partially ended process." + self debugSession interruptedProcess isTerminating ifTrue: [ SteppingATerminatingProcess signal ]. - ^ self debugSession stepOver: aContext + ^ self basicStepOver: aContext ] { #category : 'debugging actions' } diff --git a/src/Sindarin/SindarinDebugger.class.st b/src/Sindarin/SindarinDebugger.class.st index 3e407a2..b2751b4 100644 --- a/src/Sindarin/SindarinDebugger.class.st +++ b/src/Sindarin/SindarinDebugger.class.st @@ -19,9 +19,9 @@ Class { #superclass : 'Object', #traits : 'TDebugger + TSindarin', #classTraits : 'TDebugger classTrait + TSindarin classTrait', - #category : 'Sindarin-Base', + #category : 'Sindarin-Core', #package : 'Sindarin', - #tag : 'Base' + #tag : 'Core' } { #category : 'stackAccessHelpers' } @@ -86,6 +86,15 @@ SindarinDebugger >> continue [ whileFalse: [ self step ] ] +{ #category : 'stepping - steps' } +SindarinDebugger >> diveUntil: aBlock [ + "Dives into the current context (=startingContext) until the execution returns back to the starting context's sender, or satisfies aBlock condition." + + | sender | + sender := self context sender. + self stepUntil: [ self context == sender or: aBlock ] +] + { #category : 'accessing' } SindarinDebugger >> firstPCOfStatement: aStatementNode [ @@ -599,9 +608,18 @@ SindarinDebugger >> stepToReturn [ { #category : 'stepping - steps' } SindarinDebugger >> stepUntil: aBlock [ - "Steps the execution until aBlock evaluates to true" - - aBlock whileFalse: [ self step ] + "Steps the execution until aBlock evaluates to true. + Steps over ensure: blocks (primitive 198) to avoid hanging. + The hanging seems to be due to the execution of valueNoContextSwitch" + + aBlock whileFalse: [ "Stepping into primitive 198 freezes the image, we do not know why. + Stepping over the sender context fixes the freezes. + There is an open issue about understanding why: https://github.com/pharo-spec/ScriptableDebugger/issues/105" + self method primitive = 198 + ifTrue: [ + self isExecutionFinished ifFalse: [ + sindarinSession basicStepThrough: self context sender] ] + ifFalse: [ self step ] ] ] { #category : 'astAndAstMapping' } diff --git a/src/Sindarin/SindarinSkippingReturnWarning.class.st b/src/Sindarin/SindarinSkippingReturnWarning.class.st index 4298f5c..f29c889 100644 --- a/src/Sindarin/SindarinSkippingReturnWarning.class.st +++ b/src/Sindarin/SindarinSkippingReturnWarning.class.st @@ -1,3 +1,6 @@ +" +I am raised when Sindarin attempts to skip the execution of a return node, which leaves an unspecified scenario to happen: what should we return if we skip a return? +" Class { #name : 'SindarinSkippingReturnWarning', #superclass : 'Warning', diff --git a/src/Sindarin/SteppingATerminatingProcess.class.st b/src/Sindarin/SteppingATerminatingProcess.class.st index c321cfb..f21097c 100644 --- a/src/Sindarin/SteppingATerminatingProcess.class.st +++ b/src/Sindarin/SteppingATerminatingProcess.class.st @@ -1,3 +1,6 @@ +" +I am raised when Sindarin attempts to step a terminated process. +" Class { #name : 'SteppingATerminatingProcess', #superclass : 'Error', diff --git a/src/Sindarin/UnhandledExceptionSignalledByADebuggedExecution.class.st b/src/Sindarin/UnhandledExceptionSignalledByADebuggedExecution.class.st index fc791b0..6b1aa7a 100644 --- a/src/Sindarin/UnhandledExceptionSignalledByADebuggedExecution.class.st +++ b/src/Sindarin/UnhandledExceptionSignalledByADebuggedExecution.class.st @@ -1,6 +1,9 @@ +" +I am raised when an exception is signalled within a debugged process that Sindarin executes. +" Class { #name : 'UnhandledExceptionSignalledByADebuggedExecution', - #superclass : 'DebuggedExecutionException', + #superclass : 'Error', #instVars : [ 'unhandledException' ],