Browse Source

- Helios debugger improvements
- ASTDebugger top context handling

Nicolas Petton 10 years ago
parent
commit
d4842bf7b5
4 changed files with 144 additions and 101 deletions
  1. 50 36
      src/Compiler-Interpreter.js
  2. 11 8
      src/Compiler-Interpreter.st
  3. 62 43
      src/Helios-Debugger.js
  4. 21 14
      src/Helios-Debugger.st

+ 50 - 36
src/Compiler-Interpreter.js

@@ -604,6 +604,24 @@ referencedClasses: []
 }),
 globals.AIContext);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isTopContext",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._innerContext())._isNil();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isTopContext",{},globals.AIContext)})},
+args: [],
+source: "isTopContext\x0a\x09^ self innerContext isNil",
+messageSends: ["isNil", "innerContext"],
+referencedClasses: []
+}),
+globals.AIContext);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "localAt:",
@@ -1236,31 +1254,30 @@ protocol: 'private',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$2,$4,$receiver;
-$1=_st(self._interpreter())._atEnd();
+var $2,$1,$3,$4,$receiver;
+$2=self._interpreter();
+$ctx1.sendIdx["interpreter"]=1;
+$1=_st($2)._atEnd();
+$ctx1.sendIdx["atEnd"]=1;
 if(smalltalk.assert($1)){
-$3=self._context();
-$ctx1.sendIdx["context"]=1;
-$2=_st($3)._outerContext();
-if(($receiver = $2) == nil || $receiver == null){
-$2;
+$3=_st(self._context())._outerContext();
+if(($receiver = $3) == nil || $receiver == null){
+$3;
 } else {
 var outerContext;
 outerContext=$receiver;
 self._context_(outerContext);
 };
-$4=self._context();
-if(($receiver = $4) == nil || $receiver == null){
-$4;
-} else {
-self._skip();
+$4=self._atEnd();
+if(! smalltalk.assert($4)){
+_st(self._interpreter())._skip();
 };
 };
 self._flushInnerContexts();
 return self}, function($ctx1) {$ctx1.fill(self,"onStep",{},globals.ASTDebugger)})},
 args: [],
-source: "onStep\x0a\x09\x22After each step, check if the interpreter is at the end,\x0a\x09and if it is move to its outer context if any, skipping its \x0a\x09current node (which was just evaluated by the current \x0a\x09interpreter).\x0a\x09\x0a\x09After each step we also flush inner contexts.\x22\x0a\x09\x0a\x09self interpreter atEnd ifTrue: [\x0a\x09\x09self context outerContext ifNotNil: [ :outerContext | \x0a\x09\x09\x09self context: outerContext ].\x0a\x09\x09self context ifNotNil: [ self skip ] ].\x0a\x09\x09\x0a\x09self flushInnerContexts",
-messageSends: ["ifTrue:", "atEnd", "interpreter", "ifNotNil:", "outerContext", "context", "context:", "skip", "flushInnerContexts"],
+source: "onStep\x0a\x09\x22After each step, check if the interpreter is at the end,\x0a\x09and if it is move to its outer context if any, skipping its \x0a\x09current node (which was just evaluated by the current \x0a\x09interpreter).\x0a\x09\x0a\x09After each step we also flush inner contexts.\x22\x0a\x09\x0a\x09self interpreter atEnd ifTrue: [\x0a\x09\x09self context outerContext ifNotNil: [ :outerContext | \x0a\x09\x09\x09self context: outerContext ].\x0a\x09\x09self atEnd ifFalse: [ self interpreter skip ] ].\x0a\x09\x09\x0a\x09self flushInnerContexts",
+messageSends: ["ifTrue:", "atEnd", "interpreter", "ifNotNil:", "outerContext", "context", "context:", "ifFalse:", "skip", "flushInnerContexts"],
 referencedClasses: []
 }),
 globals.ASTDebugger);
@@ -1272,11 +1289,17 @@ protocol: 'stepping',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-self._shouldBeImplemented();
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._atEnd();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._whileFalse_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._stepOver();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"proceed",{},globals.ASTDebugger)})},
 args: [],
-source: "proceed\x0a\x09self shouldBeImplemented",
-messageSends: ["shouldBeImplemented"],
+source: "proceed\x0a\x09[ self atEnd ] whileFalse: [ self stepOver ]",
+messageSends: ["whileFalse:", "atEnd", "stepOver"],
 referencedClasses: []
 }),
 globals.ASTDebugger);
@@ -1298,23 +1321,6 @@ referencedClasses: []
 }),
 globals.ASTDebugger);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "skip",
-protocol: 'stepping',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(self._interpreter())._skip();
-self._onStep();
-return self}, function($ctx1) {$ctx1.fill(self,"skip",{},globals.ASTDebugger)})},
-args: [],
-source: "skip\x0a\x09self interpreter skip.\x0a\x09self onStep",
-messageSends: ["skip", "interpreter", "onStep"],
-referencedClasses: []
-}),
-globals.ASTDebugger);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "stepInto",
@@ -1338,12 +1344,20 @@ protocol: 'stepping',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st(self._context())._isTopContext();
+if(smalltalk.assert($1)){
 _st(self._interpreter())._stepOver();
+} else {
+$2=self._interpreter();
+$ctx1.sendIdx["interpreter"]=1;
+_st($2)._skip();
+};
 self._onStep();
 return self}, function($ctx1) {$ctx1.fill(self,"stepOver",{},globals.ASTDebugger)})},
 args: [],
-source: "stepOver\x0a\x09self interpreter stepOver.\x0a\x09self onStep",
-messageSends: ["stepOver", "interpreter", "onStep"],
+source: "stepOver\x0a\x09self context isTopContext \x0a\x09\x09ifFalse: [ self interpreter skip ]\x0a\x09\x09ifTrue: [ self interpreter stepOver ].\x0a\x09self onStep",
+messageSends: ["ifFalse:ifTrue:", "isTopContext", "context", "skip", "interpreter", "stepOver", "onStep"],
 referencedClasses: []
 }),
 globals.ASTDebugger);

+ 11 - 8
src/Compiler-Interpreter.st

@@ -304,6 +304,12 @@ setupInterpreter: anInterpreter
 	anInterpreter push: (self innerContext receiver)
 ! !
 
+!AIContext methodsFor: 'testing'!
+
+isTopContext
+	^ self innerContext isNil
+! !
+
 !AIContext class methodsFor: 'instance creation'!
 
 fromMethodContext: aMethodContext
@@ -417,7 +423,7 @@ onStep
 	self interpreter atEnd ifTrue: [
 		self context outerContext ifNotNil: [ :outerContext | 
 			self context: outerContext ].
-		self context ifNotNil: [ self skip ] ].
+		self atEnd ifFalse: [ self interpreter skip ] ].
 		
 	self flushInnerContexts
 ! !
@@ -425,7 +431,7 @@ onStep
 !ASTDebugger methodsFor: 'stepping'!
 
 proceed
-	self shouldBeImplemented
+	[ self atEnd ] whileFalse: [ self stepOver ]
 !
 
 restart
@@ -433,17 +439,14 @@ restart
 	self flushInnerContexts
 !
 
-skip
-	self interpreter skip.
-	self onStep
-!
-
 stepInto
 	self shouldBeImplemented
 !
 
 stepOver
-	self interpreter stepOver.
+	self context isTopContext 
+		ifFalse: [ self interpreter skip ]
+		ifTrue: [ self interpreter stepOver ].
 	self onStep
 ! !
 

+ 62 - 43
src/Helios-Debugger.js

@@ -354,21 +354,20 @@ protocol: 'rendering',
 fn: function (html){
 var self=this;
 function $HLContainer(){return globals.HLContainer||(typeof HLContainer=="undefined"?nil:HLContainer)}
-function $HLHorizontalSplitter(){return globals.HLHorizontalSplitter||(typeof HLHorizontalSplitter=="undefined"?nil:HLHorizontalSplitter)}
 function $HLVerticalSplitter(){return globals.HLVerticalSplitter||(typeof HLVerticalSplitter=="undefined"?nil:HLVerticalSplitter)}
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 self._renderHeadOn_(html);
-$2=_st($HLHorizontalSplitter())._with_with_(self._stackListWidget(),_st($HLVerticalSplitter())._with_with_(self._codeWidget(),self._inspectorWidget()));
+$2=_st($HLVerticalSplitter())._with_with_(self._codeWidget(),_st($HLVerticalSplitter())._with_with_(self._stackListWidget(),self._inspectorWidget()));
 $ctx1.sendIdx["with:with:"]=1;
 $1=_st($HLContainer())._with_($2);
 _st(html)._with_($1);
 $ctx1.sendIdx["with:"]=1;
 return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLDebugger)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09self renderHeadOn: html.\x0a\x09html with: (HLContainer with: (HLHorizontalSplitter\x0a\x09\x09with: self stackListWidget\x0a\x09\x09with: (HLVerticalSplitter\x0a\x09\x09\x09with: self codeWidget\x0a\x09\x09\x09with: self inspectorWidget)))",
-messageSends: ["renderHeadOn:", "with:", "with:with:", "stackListWidget", "codeWidget", "inspectorWidget"],
-referencedClasses: ["HLContainer", "HLHorizontalSplitter", "HLVerticalSplitter"]
+source: "renderContentOn: html\x0a\x09self renderHeadOn: html.\x0a\x09html with: (HLContainer with: (HLVerticalSplitter\x0a\x09\x09with: self codeWidget\x0a\x09\x09with: (HLVerticalSplitter\x0a\x09\x09\x09with: self stackListWidget\x0a\x09\x09\x09with: self inspectorWidget)))",
+messageSends: ["renderHeadOn:", "with:", "with:with:", "codeWidget", "stackListWidget", "inspectorWidget"],
+referencedClasses: ["HLContainer", "HLVerticalSplitter"]
 }),
 globals.HLDebugger);
 
@@ -936,11 +935,11 @@ function $AIContext(){return globals.AIContext||(typeof AIContext=="undefined"?n
 return smalltalk.withContext(function($ctx1) { 
 self["@error"]=anError;
 self["@rootContext"]=_st($AIContext())._fromMethodContext_(_st(self["@error"])._context());
-_st(self._debugger())._context_(self["@rootContext"]);
+self._currentContext_(self["@rootContext"]);
 return self}, function($ctx1) {$ctx1.fill(self,"initializeFromError:",{anError:anError},globals.HLDebuggerModel)})},
 args: ["anError"],
-source: "initializeFromError: anError\x0a\x09error := anError.\x0a\x09rootContext := (AIContext fromMethodContext: error context).\x0a\x09self debugger context: rootContext",
-messageSends: ["fromMethodContext:", "context", "context:", "debugger"],
+source: "initializeFromError: anError\x0a\x09error := anError.\x0a\x09rootContext := (AIContext fromMethodContext: error context).\x0a\x09self currentContext: rootContext",
+messageSends: ["fromMethodContext:", "context", "currentContext:"],
 referencedClasses: ["AIContext"]
 }),
 globals.HLDebuggerModel);
@@ -971,14 +970,39 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 self["@rootContext"]=self._currentContext();
+$ctx1.sendIdx["currentContext"]=1;
+self._currentContext_(self._currentContext());
 return self}, function($ctx1) {$ctx1.fill(self,"onStep",{},globals.HLDebuggerModel)})},
 args: [],
-source: "onStep\x0a\x09rootContext := self currentContext",
-messageSends: ["currentContext"],
+source: "onStep\x0a\x09rootContext := self currentContext.\x0a\x09\x0a\x09\x22Force a refresh of the context list and code widget\x22\x0a\x09self currentContext: self currentContext",
+messageSends: ["currentContext", "currentContext:"],
 referencedClasses: []
 }),
 globals.HLDebuggerModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "proceed",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLDebuggerStepped(){return globals.HLDebuggerStepped||(typeof HLDebuggerStepped=="undefined"?nil:HLDebuggerStepped)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+_st(self._debugger())._proceed();
+self._onStep();
+$1=_st($HLDebuggerStepped())._new();
+_st($1)._context_(self._currentContext());
+$2=_st($1)._yourself();
+_st(self._announcer())._announce_($2);
+return self}, function($ctx1) {$ctx1.fill(self,"proceed",{},globals.HLDebuggerModel)})},
+args: [],
+source: "proceed\x0a\x09self debugger proceed.\x0a\x09self onStep.\x0a\x09\x0a\x09self announcer announce: (HLDebuggerStepped new\x0a\x09\x09context: self currentContext;\x0a\x09\x09yourself)",
+messageSends: ["proceed", "debugger", "onStep", "announce:", "announcer", "context:", "new", "currentContext", "yourself"],
+referencedClasses: ["HLDebuggerStepped"]
+}),
+globals.HLDebuggerModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "restart",
@@ -1019,29 +1043,6 @@ referencedClasses: []
 }),
 globals.HLDebuggerModel);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "skip",
-protocol: 'actions',
-fn: function (){
-var self=this;
-function $HLDebuggerStepped(){return globals.HLDebuggerStepped||(typeof HLDebuggerStepped=="undefined"?nil:HLDebuggerStepped)}
-return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-_st(self._debugger())._skip();
-self._onStep();
-$1=_st($HLDebuggerStepped())._new();
-_st($1)._context_(self._currentContext());
-$2=_st($1)._yourself();
-_st(self._announcer())._announce_($2);
-return self}, function($ctx1) {$ctx1.fill(self,"skip",{},globals.HLDebuggerModel)})},
-args: [],
-source: "skip\x0a\x09self debugger skip.\x0a\x09self onStep.\x0a\x09\x0a\x09self announcer announce: (HLDebuggerStepped new\x0a\x09\x09context: self currentContext;\x0a\x09\x09yourself)",
-messageSends: ["skip", "debugger", "onStep", "announce:", "announcer", "context:", "new", "currentContext", "yourself"],
-referencedClasses: ["HLDebuggerStepped"]
-}),
-globals.HLDebuggerModel);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "stepOver",
@@ -1264,6 +1265,22 @@ referencedClasses: []
 }),
 globals.HLStackListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "proceed",
+protocol: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._proceed();
+return self}, function($ctx1) {$ctx1.fill(self,"proceed",{},globals.HLStackListWidget)})},
+args: [],
+source: "proceed\x0a\x09self model proceed",
+messageSends: ["proceed", "model"],
+referencedClasses: []
+}),
+globals.HLStackListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "renderButtonsOn:",
@@ -1314,19 +1331,19 @@ return self._stepOver();
 $ctx2.sendIdx["onClick:"]=3;
 $8;
 $9=_st(html)._button();
-_st($9)._class_("btn skip");
-_st($9)._with_("Skip");
+_st($9)._class_("btn proceed");
+_st($9)._with_("Proceed");
 $10=_st($9)._onClick_((function(){
 return smalltalk.withContext(function($ctx3) {
-return self._skip();
+return self._proceed();
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,5)})}));
 return $10;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 $ctx1.sendIdx["with:"]=1;
 return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html},globals.HLStackListWidget)})},
 args: ["html"],
-source: "renderButtonsOn: html\x0a\x09html div \x0a\x09\x09class: 'debugger_bar'; \x0a\x09\x09with: [\x0a\x09\x09\x09html button \x0a\x09\x09\x09\x09class: 'btn restart';\x0a\x09\x09\x09\x09with: 'Restart';\x0a\x09\x09\x09\x09onClick: [ self restart ].\x0a\x09\x09\x09html button \x0a\x09\x09\x09\x09class: 'btn where';\x0a\x09\x09\x09\x09with: 'Where';\x0a\x09\x09\x09\x09onClick: [ self where ].\x0a\x09\x09\x09html button \x0a\x09\x09\x09\x09class: 'btn stepOver';\x0a\x09\x09\x09\x09with: 'Step over';\x0a\x09\x09\x09\x09onClick: [ self stepOver ].\x0a\x09\x09\x09html button \x0a\x09\x09\x09\x09class: 'btn skip';\x0a\x09\x09\x09\x09with: 'Skip';\x0a\x09\x09\x09\x09onClick: [ self skip ] ]",
-messageSends: ["class:", "div", "with:", "button", "onClick:", "restart", "where", "stepOver", "skip"],
+source: "renderButtonsOn: html\x0a\x09html div \x0a\x09\x09class: 'debugger_bar'; \x0a\x09\x09with: [\x0a\x09\x09\x09html button \x0a\x09\x09\x09\x09class: 'btn restart';\x0a\x09\x09\x09\x09with: 'Restart';\x0a\x09\x09\x09\x09onClick: [ self restart ].\x0a\x09\x09\x09html button \x0a\x09\x09\x09\x09class: 'btn where';\x0a\x09\x09\x09\x09with: 'Where';\x0a\x09\x09\x09\x09onClick: [ self where ].\x0a\x09\x09\x09html button \x0a\x09\x09\x09\x09class: 'btn stepOver';\x0a\x09\x09\x09\x09with: 'Step over';\x0a\x09\x09\x09\x09onClick: [ self stepOver ].\x0a\x09\x09\x09html button \x0a\x09\x09\x09\x09class: 'btn proceed';\x0a\x09\x09\x09\x09with: 'Proceed';\x0a\x09\x09\x09\x09onClick: [ self proceed ] ]",
+messageSends: ["class:", "div", "with:", "button", "onClick:", "restart", "where", "stepOver", "proceed"],
 referencedClasses: []
 }),
 globals.HLStackListWidget);
@@ -1366,16 +1383,18 @@ globals.HLStackListWidget);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "skip",
+selector: "selectedItem",
 protocol: 'actions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._model())._skip();
-return self}, function($ctx1) {$ctx1.fill(self,"skip",{},globals.HLStackListWidget)})},
+var $1;
+$1=_st(self._model())._currentContext();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"selectedItem",{},globals.HLStackListWidget)})},
 args: [],
-source: "skip\x0a\x09self model skip",
-messageSends: ["skip", "model"],
+source: "selectedItem\x0a   \x09^ self model currentContext",
+messageSends: ["currentContext", "model"],
 referencedClasses: []
 }),
 globals.HLStackListWidget);

+ 21 - 14
src/Helios-Debugger.st

@@ -120,10 +120,10 @@ onDebuggerStepped: anAnnouncement
 
 renderContentOn: html
 	self renderHeadOn: html.
-	html with: (HLContainer with: (HLHorizontalSplitter
-		with: self stackListWidget
+	html with: (HLContainer with: (HLVerticalSplitter
+		with: self codeWidget
 		with: (HLVerticalSplitter
-			with: self codeWidget
+			with: self stackListWidget
 			with: self inspectorWidget)))
 !
 
@@ -324,8 +324,8 @@ rootContext
 
 !HLDebuggerModel methodsFor: 'actions'!
 
-restart
-	self debugger restart.
+proceed
+	self debugger proceed.
 	self onStep.
 	
 	self announcer announce: (HLDebuggerStepped new
@@ -333,8 +333,8 @@ restart
 		yourself)
 !
 
-skip
-	self debugger skip.
+restart
+	self debugger restart.
 	self onStep.
 	
 	self announcer announce: (HLDebuggerStepped new
@@ -368,7 +368,7 @@ evaluate: aString
 initializeFromError: anError
 	error := anError.
 	rootContext := (AIContext fromMethodContext: error context).
-	self debugger context: rootContext
+	self currentContext: rootContext
 ! !
 
 !HLDebuggerModel methodsFor: 'private'!
@@ -385,7 +385,10 @@ flushInnerContexts
 !HLDebuggerModel methodsFor: 'reactions'!
 
 onStep
-	rootContext := self currentContext
+	rootContext := self currentContext.
+	
+	"Force a refresh of the context list and code widget"
+	self currentContext: self currentContext
 ! !
 
 !HLDebuggerModel methodsFor: 'testing'!
@@ -465,6 +468,10 @@ observeModel
 		to: self
 !
 
+proceed
+	self model proceed
+!
+
 restart
 	self model restart
 !
@@ -474,8 +481,8 @@ selectItem: aContext
 	super selectItem: aContext
 !
 
-skip
-	self model skip
+selectedItem
+   	^ self model currentContext
 !
 
 stepOver
@@ -512,8 +519,8 @@ renderButtonsOn: html
 				with: 'Step over';
 				onClick: [ self stepOver ].
 			html button 
-				class: 'btn skip';
-				with: 'Skip';
-				onClick: [ self skip ] ]
+				class: 'btn proceed';
+				with: 'Proceed';
+				onClick: [ self proceed ] ]
 ! !