'From Squeak3.7beta of ''1 April 2004'' [latest update: #5967] on 10 July 2004 at 2:24:56 pm'! "Change Set: DebuggerEditAndCreateMethodFixes-nk Date: 10 July 2004 Author: Ned Konz This greatly simplifies the process of incremental programming, where you can quickly write code that calls unimplemented methods, create those methods, and keep running. With this change set installed, you should be able to do this: - open a Workspace - 3 zork - get pre-debug window MNU, choose 'Create' - select class and category - edit method to read ^self - accept - proceed - prints 3. This CS has the following fixes for the Debugger: * When accepting a new method that is a quick method, pop the context because we can't step through quick methods. * When proceeding from a MNU, re-send the message so that if it was newly implemented the new definition will be re-run. This is the same behavior that existed in Squeak prior to CS 5308. * When creating a new method from the pre-debug window, open a debugger on that method immediately. * Avoid returning nil keys from #sourceMap " ! !Object methodsFor: 'error handling' stamp: 'nk 7/10/2004 09:43'! doesNotUnderstand: aMessage "Handle the fact that there was an attempt to send the given message to the receiver but the receiver does not understand this message (typically sent from the machine when a message is sent to the receiver and no method is defined for that selector)." "Testing: (3 activeProcess)" (Preferences autoAccessors and: [self tryToDefineVariableAccess: aMessage]) ifTrue: [^ aMessage sentTo: self]. MessageNotUnderstood new message: aMessage; receiver: self; signal. ^ aMessage sentTo: self. ! ! !Debugger methodsFor: 'accessing' stamp: 'nk 7/10/2004 14:17'! contents: aText notifying: aController "The retrieved information has changed and its source must now be updated. In this case, the retrieved information is the method of the selected context." | selector classOfMethod category h ctxt newMethod | contextStackIndex = 0 ifTrue: [^ false]. self selectedContext isExecutingBlock ifTrue: [h := self selectedContext finalBlockHome. h ifNil: [self inform: 'Method not found for block, can''t edit'. ^ false]. (self confirm: 'I will have to revert to the method from which this block originated. Is that OK?') ifTrue: [self resetContext: h] ifFalse: [^ false]]. classOfMethod := self selectedClass. category := self selectedMessageCategoryName. selector := self selectedClass parserClass new parseSelector: aText. selector == self selectedMessageName ifFalse: [self inform: 'can''t change selector'. ^ false]. selector := classOfMethod compile: aText classified: category notifying: aController. selector ifNil: [^ false]. "compile cancelled" contents := aText. newMethod := classOfMethod compiledMethodAt: selector. newMethod isQuick ifTrue: [ self down. self selectedContext jump: (self selectedContext previousPc - self selectedContext pc) ]. ctxt := interruptedProcess popTo: self selectedContext. ctxt == self selectedContext ifFalse: [ self inform: 'Method saved, but current context unchanged because of unwind error. Click OK to see error'. ] ifTrue: [ newMethod isQuick ifFalse: [ interruptedProcess restartTopWith: newMethod; stepToSendOrReturn ]. contextVariablesInspector object: nil. theMethodNode := Preferences browseWithPrettyPrint ifTrue: [ctxt methodNodeFormattedAndDecorated: Preferences colorWhenPrettyPrinting] ifFalse: [ctxt methodNode]. sourceMap := theMethodNode sourceMap. tempNames := theMethodNode tempNames. ]. self resetContext: ctxt. Smalltalk isMorphic ifTrue: [ World addAlarm: #changed: withArguments: #(contentsSelection) for: self at: (Time millisecondClockValue + 200) ]. ^ true ! ! !Debugger methodsFor: 'context stack menu' stamp: 'nk 7/10/2004 14:11'! implement: aMessage inClass: aClass | category | category := self askForCategoryIn: aClass default: 'as yet unclassified'. aClass compile: aMessage createStubMethod classified: category. self setContentsToForceRefetch. self selectedContext privRefreshWith: (aClass lookupSelector: aMessage selector). self resetContext: self selectedContext. self debug. ! ! !Debugger methodsFor: 'code pane' stamp: 'tk 4/15/1998 18:31'! contentsSelection ^ self pcRange! ! !Debugger methodsFor: 'private' stamp: 'nk 7/10/2004 12:31'! createMethod "Should only be called when this Debugger was created in response to a MessageNotUnderstood exception. Create a stub for the method that was missing and proceed into it." | msg chosenClass | msg _ contextStackTop tempAt: 1. chosenClass _ self askForSuperclassOf: contextStackTop receiver class toImplement: msg selector ifCancel: [^self]. self implement: msg inClass: chosenClass. ! ! !Debugger methodsFor: 'private' stamp: 'nk 7/10/2004 12:51'! resetContext: aContext "Used when a new context becomes top-of-stack, for instance when the method of the selected context is re-compiled, or the simulator steps or returns to a new method. There is room for much optimization here, first to save recomputing the whole stack list (and text), and secondly to avoid recomposing all that text (by editing the paragraph instead of recreating it)." | oldContext | oldContext _ self selectedContext. contextStackTop _ aContext. self newStack: contextStackTop contextStack. self changed: #contextStackList. self contextStackIndex: 1 oldContextWas: oldContext. self contentsChanged. ! ! !ParseNode methodsFor: 'code generation' stamp: 'nk 7/10/2004 10:04'! pc "Used by encoder source mapping." ^pc ifNil: [ 0 ] ! ! !Process methodsFor: 'changing suspended state' stamp: 'nk 7/10/2004 11:16'! restartTopWith: method "Rollback top context and replace with new method. Assumes self is suspended" method isQuick ifTrue: [ self popTo: suspendedContext sender ] ifFalse: [ suspendedContext privRefreshWith: method ]. ! ! ReturnNode removeSelector: #pc! MessageNode removeSelector: #pc! Debugger removeSelector: #changed:! Debugger removeSelector: #contentsChanged!