Bläddra i källkod

Helios debugger improvements
- adds AIContext >> evaluateNode:
- uses AIContext >> evaluateNode: in the code widget of the debugger
- removes unused method Node >> extent
- adds Environment >> interpret:inContext:

Nicolas Petton 10 år sedan
förälder
incheckning
7dc08fe9ea

+ 0 - 24
js/Compiler-AST.js

@@ -1315,30 +1315,6 @@ referencedClasses: []
 }),
 globals.MethodNode);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "extent",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $4,$3,$2,$1;
-$4=self._source();
-$ctx1.sendIdx["source"]=1;
-$3=_st($4)._lines();
-$ctx1.sendIdx["lines"]=1;
-$2=_st($3)._size();
-$ctx1.sendIdx["size"]=1;
-$1=_st($2).__at(_st(_st(_st(_st(self._source())._lines())._last())._size()).__plus((1)));
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"extent",{},globals.MethodNode)})},
-args: [],
-source: "extent\x0a\x09^ self source lines size @ (self source lines last size + 1)",
-messageSends: ["@", "size", "lines", "source", "+", "last"],
-referencedClasses: []
-}),
-globals.MethodNode);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "messageSends",

+ 45 - 114
js/Compiler-Interpreter.js

@@ -294,6 +294,30 @@ referencedClasses: []
 }),
 globals.AIContext);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluateNode:",
+protocol: 'evaluating',
+fn: function (aNode){
+var self=this;
+function $ASTInterpreter(){return globals.ASTInterpreter||(typeof ASTInterpreter=="undefined"?nil:ASTInterpreter)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=_st($ASTInterpreter())._new();
+_st($2)._context_(self);
+_st($2)._node_(_st(aNode)._nextChild());
+_st($2)._proceed();
+$3=_st($2)._result();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"evaluateNode:",{aNode:aNode},globals.AIContext)})},
+args: ["aNode"],
+source: "evaluateNode: aNode\x0a\x09^ ASTInterpreter new\x0a\x09\x09context: self;\x0a\x09\x09node: aNode nextChild;\x0a\x09\x09proceed;\x0a\x09\x09result",
+messageSends: ["context:", "new", "node:", "nextChild", "proceed", "result"],
+referencedClasses: ["ASTInterpreter"]
+}),
+globals.AIContext);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "evaluatedSelector",
@@ -711,12 +735,20 @@ protocol: 'accessing',
 fn: function (anAIContext){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
+var $1;
 self["@outerContext"]=anAIContext;
-_st(self["@outerContext"])._innerContext_(self);
+$1=self["@outerContext"];
+if(($receiver = $1) == nil || $receiver == null){
+$1;
+} else {
+var context;
+context=$receiver;
+_st(context)._innerContext_(self);
+};
 return self}, function($ctx1) {$ctx1.fill(self,"outerContext:",{anAIContext:anAIContext},globals.AIContext)})},
 args: ["anAIContext"],
-source: "outerContext: anAIContext\x0a\x09outerContext := anAIContext.\x0a\x09outerContext innerContext: self",
-messageSends: ["innerContext:"],
+source: "outerContext: anAIContext\x0a\x09outerContext := anAIContext.\x0a\x09outerContext ifNotNil: [ :context | \x0a\x09\x09context innerContext: self ]",
+messageSends: ["ifNotNil:", "innerContext:"],
 referencedClasses: []
 }),
 globals.AIContext);
@@ -925,29 +957,6 @@ referencedClasses: []
 }),
 globals.ASTDebugger);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "buildAST",
-protocol: 'initialization',
-fn: function (){
-var self=this;
-var ast;
-function $Smalltalk(){return globals.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
-function $SemanticAnalyzer(){return globals.SemanticAnalyzer||(typeof SemanticAnalyzer=="undefined"?nil:SemanticAnalyzer)}
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-ast=_st($Smalltalk())._parse_(_st(self._method())._source());
-_st(_st($SemanticAnalyzer())._on_(_st(_st(self._context())._receiver())._class()))._visit_(ast);
-$1=ast;
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"buildAST",{ast:ast},globals.ASTDebugger)})},
-args: [],
-source: "buildAST\x0a\x09\x22Build the AST tree from the method source code.\x0a\x09The AST is annotated with a SemanticAnalyzer,\x0a\x09to know the semantics and bindings of each node needed for later debugging\x22\x0a\x09\x0a\x09| ast |\x0a\x09\x0a\x09ast := Smalltalk parse: self method source.\x0a\x09(SemanticAnalyzer on: self context receiver class)\x0a\x09\x09visit: ast.\x0a\x09\x0a\x09^ ast",
-messageSends: ["parse:", "source", "method", "visit:", "on:", "class", "receiver", "context"],
-referencedClasses: ["Smalltalk", "SemanticAnalyzer"]
-}),
-globals.ASTDebugger);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "context",
@@ -980,64 +989,6 @@ referencedClasses: []
 }),
 globals.ASTDebugger);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "defaultInterpreterClass",
-protocol: 'defaults',
-fn: function (){
-var self=this;
-function $ASTInterpreter(){return globals.ASTInterpreter||(typeof ASTInterpreter=="undefined"?nil:ASTInterpreter)}
-return $ASTInterpreter();
-},
-args: [],
-source: "defaultInterpreterClass\x0a\x09^ ASTInterpreter",
-messageSends: [],
-referencedClasses: ["ASTInterpreter"]
-}),
-globals.ASTDebugger);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "initializeInterpreter",
-protocol: 'initialization',
-fn: function (){
-var self=this;
-var ast,next;
-function $ASTPCNodeVisitor(){return globals.ASTPCNodeVisitor||(typeof ASTPCNodeVisitor=="undefined"?nil:ASTPCNodeVisitor)}
-return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-ast=self._buildAST();
-$1=_st($ASTPCNodeVisitor())._new();
-_st($1)._context_(self._context());
-_st($1)._visit_(ast);
-$2=_st($1)._currentNode();
-next=$2;
-_st(self._interpreter())._node_(next);
-return self}, function($ctx1) {$ctx1.fill(self,"initializeInterpreter",{ast:ast,next:next},globals.ASTDebugger)})},
-args: [],
-source: "initializeInterpreter\x0a\x09| ast next |\x0a\x09ast := self buildAST.\x0a\x09next := ASTPCNodeVisitor new\x0a\x09\x09context: self context;\x0a\x09\x09visit: ast;\x0a\x09\x09currentNode.\x0a\x09self interpreter node: next",
-messageSends: ["buildAST", "context:", "new", "context", "visit:", "currentNode", "node:", "interpreter"],
-referencedClasses: ["ASTPCNodeVisitor"]
-}),
-globals.ASTDebugger);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "initializeWithContext:",
-protocol: 'initialization',
-fn: function (aContext){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self._context_(aContext);
-self._initializeInterpreter();
-return self}, function($ctx1) {$ctx1.fill(self,"initializeWithContext:",{aContext:aContext},globals.ASTDebugger)})},
-args: ["aContext"],
-source: "initializeWithContext: aContext\x0a\x09\x22TODO: do we need to handle block contexts?\x22\x0a\x09\x0a\x09self context: aContext.\x0a\x09self initializeInterpreter",
-messageSends: ["context:", "initializeInterpreter"],
-referencedClasses: []
-}),
-globals.ASTDebugger);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "interpreter",
@@ -1045,34 +996,13 @@ protocol: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@interpreter"];
-if(($receiver = $2) == nil || $receiver == null){
-self["@interpreter"]=_st(self._defaultInterpreterClass())._new();
-$1=self["@interpreter"];
-} else {
-$1=$2;
-};
+var $1;
+$1=_st(self._context())._interpreter();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"interpreter",{},globals.ASTDebugger)})},
 args: [],
-source: "interpreter\x0a\x09^ interpreter ifNil: [ interpreter := self defaultInterpreterClass new ]",
-messageSends: ["ifNil:", "new", "defaultInterpreterClass"],
-referencedClasses: []
-}),
-globals.ASTDebugger);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "interpreter:",
-protocol: 'accessing',
-fn: function (anInterpreter){
-var self=this;
-self["@interpreter"]=anInterpreter;
-return self},
-args: ["anInterpreter"],
-source: "interpreter: anInterpreter\x0a\x09interpreter := anInterpreter",
-messageSends: [],
+source: "interpreter\x0a\x09^ self context interpreter",
+messageSends: ["interpreter", "context"],
 referencedClasses: []
 }),
 globals.ASTDebugger);
@@ -1184,11 +1114,12 @@ protocol: 'stepping',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
+self._flushOuterContexts();
 _st(self._interpreter())._stepOver();
 return self}, function($ctx1) {$ctx1.fill(self,"stepOver",{},globals.ASTDebugger)})},
 args: [],
-source: "stepOver\x0a\x09self interpreter stepOver",
-messageSends: ["stepOver", "interpreter"],
+source: "stepOver\x0a\x09self flushOuterContexts.\x0a\x09self interpreter stepOver",
+messageSends: ["flushOuterContexts", "stepOver", "interpreter"],
 referencedClasses: []
 }),
 globals.ASTDebugger);
@@ -1203,14 +1134,14 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$3,$1;
 $2=self._new();
-_st($2)._initializeWithContext_(aContext);
+_st($2)._context_(aContext);
 $3=_st($2)._yourself();
 $1=$3;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"context:",{aContext:aContext},globals.ASTDebugger.klass)})},
 args: ["aContext"],
-source: "context: aContext\x0a\x09^ self new\x0a\x09\x09initializeWithContext: aContext;\x0a\x09\x09yourself",
-messageSends: ["initializeWithContext:", "new", "yourself"],
+source: "context: aContext\x0a\x09^ self new\x0a\x09\x09context: aContext;\x0a\x09\x09yourself",
+messageSends: ["context:", "new", "yourself"],
 referencedClasses: []
 }),
 globals.ASTDebugger.klass);

+ 159 - 16
js/Helios-Debugger.js

@@ -111,14 +111,26 @@ protocol: 'accessing',
 fn: function (){
 var self=this;
 function $HLDebuggerCodeWidget(){return globals.HLDebuggerCodeWidget||(typeof HLDebuggerCodeWidget=="undefined"?nil:HLDebuggerCodeWidget)}
+function $HLDebuggerCodeModel(){return globals.HLDebuggerCodeModel||(typeof HLDebuggerCodeModel=="undefined"?nil:HLDebuggerCodeModel)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$4,$1;
+var $2,$3,$4,$6,$7,$8,$9,$5,$10,$1;
 $2=self["@codeWidget"];
 if(($receiver = $2) == nil || $receiver == null){
 $3=_st($HLDebuggerCodeWidget())._new();
+$ctx1.sendIdx["new"]=1;
+$4=$3;
+$6=_st($HLDebuggerCodeModel())._new();
+$7=$6;
+$8=self._model();
+$ctx1.sendIdx["model"]=1;
+_st($7)._debuggerModel_($8);
+$9=_st($6)._yourself();
+$ctx1.sendIdx["yourself"]=1;
+$5=$9;
+_st($4)._model_($5);
 _st($3)._browserModel_(self._model());
-$4=_st($3)._yourself();
-self["@codeWidget"]=$4;
+$10=_st($3)._yourself();
+self["@codeWidget"]=$10;
 $1=self["@codeWidget"];
 } else {
 $1=$2;
@@ -126,9 +138,9 @@ $1=$2;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"codeWidget",{},globals.HLDebugger)})},
 args: [],
-source: "codeWidget\x0a\x09^ codeWidget ifNil: [ codeWidget := HLDebuggerCodeWidget new\x0a\x09\x09browserModel: self model;\x0a\x09\x09yourself ]",
-messageSends: ["ifNil:", "browserModel:", "new", "model", "yourself"],
-referencedClasses: ["HLDebuggerCodeWidget"]
+source: "codeWidget\x0a\x09^ codeWidget ifNil: [ codeWidget := HLDebuggerCodeWidget new\x0a\x09\x09model: (HLDebuggerCodeModel new\x0a\x09\x09\x09debuggerModel: self model;\x0a\x09\x09\x09yourself);\x0a\x09\x09browserModel: self model;\x0a\x09\x09yourself ]",
+messageSends: ["ifNil:", "model:", "new", "debuggerModel:", "model", "yourself", "browserModel:"],
+referencedClasses: ["HLDebuggerCodeWidget", "HLDebuggerCodeModel"]
 }),
 globals.HLDebugger);
 
@@ -398,6 +410,59 @@ referencedClasses: []
 globals.HLDebugger.klass);
 
 
+smalltalk.addClass('HLDebuggerCodeModel', globals.HLCodeModel, ['debuggerModel'], 'Helios-Debugger');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "debuggerModel",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@debuggerModel"];
+return $1;
+},
+args: [],
+source: "debuggerModel\x0a\x09^ debuggerModel",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLDebuggerCodeModel);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "debuggerModel:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@debuggerModel"]=anObject;
+return self},
+args: ["anObject"],
+source: "debuggerModel: anObject\x0a\x09debuggerModel := anObject",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLDebuggerCodeModel);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "doIt:",
+protocol: 'actions',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._debuggerModel())._evaluate_(aString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"doIt:",{aString:aString},globals.HLDebuggerCodeModel)})},
+args: ["aString"],
+source: "doIt: aString\x0a\x09^ self debuggerModel evaluate: aString",
+messageSends: ["evaluate:", "debuggerModel"],
+referencedClasses: []
+}),
+globals.HLDebuggerCodeModel);
+
+
+
 smalltalk.addClass('HLDebuggerCodeWidget', globals.HLBrowserCodeWidget, [], 'Helios-Debugger');
 smalltalk.addMethod(
 smalltalk.method({
@@ -591,7 +656,7 @@ globals.HLDebuggerCodeWidget);
 
 
 smalltalk.addClass('HLDebuggerModel', globals.HLToolModel, ['rootContext', 'currentContext', 'contexts'], 'Helios-Debugger');
-globals.HLDebuggerModel.comment="I am a model for Helios debugging.\x0a\x0aMy instances hold a reference to an `AIContext` instance, built from a `MethodContext`. The context should be the root of the context stack.";
+globals.HLDebuggerModel.comment="I am a model for debugging Amber code in Helios.\x0a\x0aMy instances hold a reference to an `AIContext` instance, built from a `MethodContext`. The context should be the root of the context stack.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "contexts",
@@ -660,6 +725,45 @@ referencedClasses: ["HLDebuggerContextSelected"]
 }),
 globals.HLDebuggerModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluate:",
+protocol: 'evaluating',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._environment())._interpret_inContext_(aString,self._currentContext());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"evaluate:",{aString:aString},globals.HLDebuggerModel)})},
+args: ["aString"],
+source: "evaluate: aString\x0a\x09^ self environment \x0a\x09\x09interpret: aString \x0a\x09\x09inContext: self currentContext",
+messageSends: ["interpret:inContext:", "environment", "currentContext"],
+referencedClasses: []
+}),
+globals.HLDebuggerModel);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "flushInnerContexts",
+protocol: 'private',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._currentContext();
+$ctx1.sendIdx["currentContext"]=1;
+_st($1)._innerContext_(nil);
+self["@rootContext"]=self._currentContext();
+self._initializeContexts();
+return self}, function($ctx1) {$ctx1.fill(self,"flushInnerContexts",{},globals.HLDebuggerModel)})},
+args: [],
+source: "flushInnerContexts\x0a\x09\x22When stepping, the inner contexts are not relevent anymore,\x0a\x09and can be flushed\x22\x0a\x09\x0a\x09self currentContext innerContext: nil.\x0a\x09rootContext := self currentContext.\x0a\x09self initializeContexts",
+messageSends: ["innerContext:", "currentContext", "initializeContexts"],
+referencedClasses: []
+}),
+globals.HLDebuggerModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "initializeContexts",
@@ -700,7 +804,7 @@ self["@rootContext"]=_st($AIContext())._fromMethodContext_(aMethodContext);
 self._initializeContexts();
 return self}, function($ctx1) {$ctx1.fill(self,"initializeFromContext:",{aMethodContext:aMethodContext},globals.HLDebuggerModel)})},
 args: ["aMethodContext"],
-source: "initializeFromContext: aMethodContext\x0a\x09rootContext := AIContext fromMethodContext: aMethodContext.\x0a\x09self initializeContexts",
+source: "initializeFromContext: aMethodContext\x0a\x09rootContext := (AIContext fromMethodContext: aMethodContext).\x0a\x09self initializeContexts",
 messageSends: ["fromMethodContext:", "initializeContexts"],
 referencedClasses: ["AIContext"]
 }),
@@ -752,14 +856,15 @@ function $HLDebuggerStepped(){return globals.HLDebuggerStepped||(typeof HLDebugg
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 _st(self._interpreter())._restart();
+self._flushInnerContexts();
 $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,"restart",{},globals.HLDebuggerModel)})},
 args: [],
-source: "restart\x0a\x09self interpreter restart.\x0a\x09self announcer announce: (HLDebuggerStepped new\x0a\x09\x09context: self currentContext;\x0a\x09\x09yourself)",
-messageSends: ["restart", "interpreter", "announce:", "announcer", "context:", "new", "currentContext", "yourself"],
+source: "restart\x0a\x09self interpreter restart.\x0a\x09self flushInnerContexts.\x0a\x09\x0a\x09self announcer announce: (HLDebuggerStepped new\x0a\x09\x09context: self currentContext;\x0a\x09\x09yourself)",
+messageSends: ["restart", "interpreter", "flushInnerContexts", "announce:", "announcer", "context:", "new", "currentContext", "yourself"],
 referencedClasses: ["HLDebuggerStepped"]
 }),
 globals.HLDebuggerModel);
@@ -791,14 +896,15 @@ function $HLDebuggerStepped(){return globals.HLDebuggerStepped||(typeof HLDebugg
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 _st(self._interpreter())._skip();
+self._flushInnerContexts();
 $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 interpreter skip.\x0a\x09self announcer announce: (HLDebuggerStepped new\x0a\x09\x09context: self currentContext;\x0a\x09\x09yourself)",
-messageSends: ["skip", "interpreter", "announce:", "announcer", "context:", "new", "currentContext", "yourself"],
+source: "skip\x0a\x09self interpreter skip.\x0a\x09self flushInnerContexts.\x0a\x09\x0a\x09self announcer announce: (HLDebuggerStepped new\x0a\x09\x09context: self currentContext;\x0a\x09\x09yourself)",
+messageSends: ["skip", "interpreter", "flushInnerContexts", "announce:", "announcer", "context:", "new", "currentContext", "yourself"],
 referencedClasses: ["HLDebuggerStepped"]
 }),
 globals.HLDebuggerModel);
@@ -813,14 +919,15 @@ function $HLDebuggerStepped(){return globals.HLDebuggerStepped||(typeof HLDebugg
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 _st(self._interpreter())._stepOver();
+self._flushInnerContexts();
 $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,"stepOver",{},globals.HLDebuggerModel)})},
 args: [],
-source: "stepOver\x0a\x09self interpreter stepOver.\x0a\x09self announcer announce: (HLDebuggerStepped new\x0a\x09\x09context: self currentContext;\x0a\x09\x09yourself)",
-messageSends: ["stepOver", "interpreter", "announce:", "announcer", "context:", "new", "currentContext", "yourself"],
+source: "stepOver\x0a\x09self interpreter stepOver.\x0a\x09self flushInnerContexts.\x0a\x09\x0a\x09self announcer announce: (HLDebuggerStepped new\x0a\x09\x09context: self currentContext;\x0a\x09\x09yourself)",
+messageSends: ["stepOver", "interpreter", "flushInnerContexts", "announce:", "announcer", "context:", "new", "currentContext", "yourself"],
 referencedClasses: ["HLDebuggerStepped"]
 }),
 globals.HLDebuggerModel);
@@ -954,6 +1061,41 @@ referencedClasses: []
 }),
 globals.HLStackListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "observeModel",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLDebuggerStepped(){return globals.HLDebuggerStepped||(typeof HLDebuggerStepped=="undefined"?nil:HLDebuggerStepped)}
+return smalltalk.withContext(function($ctx1) { 
+globals.HLStackListWidget.superclass.fn.prototype._observeModel.apply(_st(self), []);
+_st(_st(self._model())._announcer())._on_send_to_($HLDebuggerStepped(),"onDebuggerStepped:",self);
+return self}, function($ctx1) {$ctx1.fill(self,"observeModel",{},globals.HLStackListWidget)})},
+args: [],
+source: "observeModel\x0a\x09super observeModel.\x0a\x09\x0a\x09self model announcer \x0a\x09\x09on: HLDebuggerStepped\x0a\x09\x09send: #onDebuggerStepped:\x0a\x09\x09to: self",
+messageSends: ["observeModel", "on:send:to:", "announcer", "model"],
+referencedClasses: ["HLDebuggerStepped"]
+}),
+globals.HLStackListWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onDebuggerStepped:",
+protocol: 'reactions',
+fn: function (anAnnouncement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@items"]=nil;
+self._refresh();
+return self}, function($ctx1) {$ctx1.fill(self,"onDebuggerStepped:",{anAnnouncement:anAnnouncement},globals.HLStackListWidget)})},
+args: ["anAnnouncement"],
+source: "onDebuggerStepped: anAnnouncement\x0a\x09items := nil.\x0a\x09self refresh",
+messageSends: ["refresh"],
+referencedClasses: []
+}),
+globals.HLStackListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "renderButtonsOn:",
@@ -1045,10 +1187,11 @@ fn: function (aContext){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 _st(self._model())._currentContext_(aContext);
+globals.HLStackListWidget.superclass.fn.prototype._selectItem_.apply(_st(self), [aContext]);
 return self}, function($ctx1) {$ctx1.fill(self,"selectItem:",{aContext:aContext},globals.HLStackListWidget)})},
 args: ["aContext"],
-source: "selectItem: aContext\x0a   \x09self model currentContext: aContext",
-messageSends: ["currentContext:", "model"],
+source: "selectItem: aContext\x0a   \x09self model currentContext: aContext.\x0a\x09super selectItem: aContext",
+messageSends: ["currentContext:", "model", "selectItem:"],
 referencedClasses: []
 }),
 globals.HLStackListWidget);

+ 38 - 1
js/Kernel-Infrastructure.js

@@ -512,7 +512,7 @@ globals.Environment);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "eval:on:",
-protocol: 'actions',
+protocol: 'evaluating',
 fn: function (aString,aReceiver){
 var self=this;
 var compiler;
@@ -585,6 +585,43 @@ referencedClasses: ["Inspector"]
 }),
 globals.Environment);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "interpret:inContext:",
+protocol: 'evaluating',
+fn: function (aString,anAIContext){
+var self=this;
+var compiler,ast;
+function $Compiler(){return globals.Compiler||(typeof Compiler=="undefined"?nil:Compiler)}
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+function $SemanticAnalyzer(){return globals.SemanticAnalyzer||(typeof SemanticAnalyzer=="undefined"?nil:SemanticAnalyzer)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+var $early={};
+try {
+compiler=_st($Compiler())._new();
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
+ast=_st(compiler)._parseExpression_(aString);
+return ast;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(ex){
+return smalltalk.withContext(function($ctx2) {
+$1=self._alert_(_st(ex)._messageText());
+throw $early=[$1];
+}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})}));
+_st(_st($SemanticAnalyzer())._on_(_st(_st(anAIContext)._receiver())._class()))._visit_(ast);
+$2=_st(anAIContext)._evaluateNode_(ast);
+return $2;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"interpret:inContext:",{aString:aString,anAIContext:anAIContext,compiler:compiler,ast:ast},globals.Environment)})},
+args: ["aString", "anAIContext"],
+source: "interpret: aString inContext: anAIContext\x0a\x09\x22Similar to #eval:on:, with the following differences:\x0a\x09- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`\x0a\x09- instead of evaluating against a receiver, evaluate in the context of `anAIContext`\x22\x0a\x0a\x09| compiler ast |\x0a\x09compiler := Compiler new.\x0a\x09[ ast := compiler parseExpression: aString ] on: Error do: [ :ex |\x0a\x09\x09^ self alert: ex messageText ].\x0a\x09(SemanticAnalyzer on: anAIContext receiver class)\x0a\x09\x09visit: ast.\x0a\x09^ anAIContext evaluateNode: ast",
+messageSends: ["new", "on:do:", "parseExpression:", "alert:", "messageText", "visit:", "on:", "class", "receiver", "evaluateNode:"],
+referencedClasses: ["Compiler", "Error", "SemanticAnalyzer"]
+}),
+globals.Environment);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "moveClass:toPackage:",

+ 0 - 4
st/Compiler-AST.st

@@ -407,10 +407,6 @@ classReferences: aCollection
 	classReferences := aCollection
 !
 
-extent
-	^ self source lines size @ (self source lines last size + 1)
-!
-
 messageSends
 	^ self sendIndexes keys
 !

+ 15 - 46
st/Compiler-Interpreter.st

@@ -167,7 +167,8 @@ outerContext
 
 outerContext: anAIContext
 	outerContext := anAIContext.
-	outerContext innerContext: self
+	outerContext ifNotNil: [ :context | 
+		context innerContext: self ]
 !
 
 selector
@@ -190,6 +191,16 @@ sendIndexes: aDictionary
 	sendIndexes := aDictionary
 ! !
 
+!AIContext methodsFor: 'evaluating'!
+
+evaluateNode: aNode
+	^ ASTInterpreter new
+		context: self;
+		node: aNode nextChild;
+		proceed;
+		result
+! !
+
 !AIContext methodsFor: 'factory'!
 
 newBlockContext
@@ -321,11 +332,7 @@ context: aContext
 !
 
 interpreter
-	^ interpreter ifNil: [ interpreter := self defaultInterpreterClass new ]
-!
-
-interpreter: anInterpreter
-	interpreter := anInterpreter
+	^ self context interpreter
 !
 
 method
@@ -336,45 +343,6 @@ nextNode
 	^ self interpreter nextNode
 ! !
 
-!ASTDebugger methodsFor: 'defaults'!
-
-defaultInterpreterClass
-	^ ASTInterpreter
-! !
-
-!ASTDebugger methodsFor: 'initialization'!
-
-buildAST
-	"Build the AST tree from the method source code.
-	The AST is annotated with a SemanticAnalyzer,
-	to know the semantics and bindings of each node needed for later debugging"
-	
-	| ast |
-	
-	ast := Smalltalk parse: self method source.
-	(SemanticAnalyzer on: self context receiver class)
-		visit: ast.
-	
-	^ ast
-!
-
-initializeInterpreter
-	| ast next |
-	ast := self buildAST.
-	next := ASTPCNodeVisitor new
-		context: self context;
-		visit: ast;
-		currentNode.
-	self interpreter node: next
-!
-
-initializeWithContext: aContext
-	"TODO: do we need to handle block contexts?"
-	
-	self context: aContext.
-	self initializeInterpreter
-! !
-
 !ASTDebugger methodsFor: 'stepping'!
 
 proceed
@@ -394,6 +362,7 @@ stepInto
 !
 
 stepOver
+	self flushOuterContexts.
 	self interpreter stepOver
 ! !
 
@@ -407,7 +376,7 @@ atEnd
 
 context: aContext
 	^ self new
-		initializeWithContext: aContext;
+		context: aContext;
 		yourself
 ! !
 

+ 68 - 3
st/Helios-Debugger.st

@@ -53,6 +53,9 @@ I am the main widget for the Helios debugger.!
 
 codeWidget
 	^ codeWidget ifNil: [ codeWidget := HLDebuggerCodeWidget new
+		model: (HLDebuggerCodeModel new
+			debuggerModel: self model;
+			yourself);
 		browserModel: self model;
 		yourself ]
 !
@@ -143,6 +146,26 @@ on: aMethodContext
 		yourself
 ! !
 
+HLCodeModel subclass: #HLDebuggerCodeModel
+	instanceVariableNames: 'debuggerModel'
+	package: 'Helios-Debugger'!
+
+!HLDebuggerCodeModel methodsFor: 'accessing'!
+
+debuggerModel
+	^ debuggerModel
+!
+
+debuggerModel: anObject
+	debuggerModel := anObject
+! !
+
+!HLDebuggerCodeModel methodsFor: 'actions'!
+
+doIt: aString
+	^ self debuggerModel evaluate: aString
+! !
+
 HLBrowserCodeWidget subclass: #HLDebuggerCodeWidget
 	instanceVariableNames: ''
 	package: 'Helios-Debugger'!
@@ -219,7 +242,7 @@ HLToolModel subclass: #HLDebuggerModel
 	instanceVariableNames: 'rootContext currentContext contexts'
 	package: 'Helios-Debugger'!
 !HLDebuggerModel commentStamp!
-I am a model for Helios debugging.
+I am a model for debugging Amber code in Helios.
 
 My instances hold a reference to an `AIContext` instance, built from a `MethodContext`. The context should be the root of the context stack.!
 
@@ -259,6 +282,8 @@ rootContext
 
 restart
 	self interpreter restart.
+	self flushInnerContexts.
+	
 	self announcer announce: (HLDebuggerStepped new
 		context: self currentContext;
 		yourself)
@@ -266,6 +291,8 @@ restart
 
 skip
 	self interpreter skip.
+	self flushInnerContexts.
+	
 	self announcer announce: (HLDebuggerStepped new
 		context: self currentContext;
 		yourself)
@@ -273,6 +300,8 @@ skip
 
 stepOver
 	self interpreter stepOver.
+	self flushInnerContexts.
+	
 	self announcer announce: (HLDebuggerStepped new
 		context: self currentContext;
 		yourself)
@@ -282,6 +311,14 @@ where
 	self announcer announce: HLDebuggerWhere new
 ! !
 
+!HLDebuggerModel methodsFor: 'evaluating'!
+
+evaluate: aString
+	^ self environment 
+		interpret: aString 
+		inContext: self currentContext
+! !
+
 !HLDebuggerModel methodsFor: 'initialization'!
 
 initializeContexts
@@ -298,7 +335,18 @@ initializeContexts
 !
 
 initializeFromContext: aMethodContext
-	rootContext := AIContext fromMethodContext: aMethodContext.
+	rootContext := (AIContext fromMethodContext: aMethodContext).
+	self initializeContexts
+! !
+
+!HLDebuggerModel methodsFor: 'private'!
+
+flushInnerContexts
+	"When stepping, the inner contexts are not relevent anymore,
+	and can be flushed"
+	
+	self currentContext innerContext: nil.
+	rootContext := self currentContext.
 	self initializeContexts
 ! !
 
@@ -352,12 +400,22 @@ label
 
 !HLStackListWidget methodsFor: 'actions'!
 
+observeModel
+	super observeModel.
+	
+	self model announcer 
+		on: HLDebuggerStepped
+		send: #onDebuggerStepped:
+		to: self
+!
+
 restart
 	self model restart
 !
 
 selectItem: aContext
-   	self model currentContext: aContext
+   	self model currentContext: aContext.
+	super selectItem: aContext
 !
 
 skip
@@ -372,6 +430,13 @@ where
 	self model where
 ! !
 
+!HLStackListWidget methodsFor: 'reactions'!
+
+onDebuggerStepped: anAnnouncement
+	items := nil.
+	self refresh
+! !
+
 !HLStackListWidget methodsFor: 'rendering'!
 
 renderButtonsOn: html

+ 24 - 8
st/Kernel-Infrastructure.st

@@ -146,14 +146,6 @@ copyClass: aClass to: aClassName
 	ClassBuilder new copyClass: aClass named: aClassName
 !
 
-eval: aString on: aReceiver
-	| compiler |
-	compiler := Compiler new.
-	[ compiler parseExpression: aString ] on: Error do: [ :ex |
-		^ self alert: ex messageText ].
-	^ compiler evaluateExpression: aString on: aReceiver
-!
-
 inspect: anObject
 	Inspector inspect: anObject
 !
@@ -251,6 +243,30 @@ evaluate: aBlock on: anErrorClass do: exceptionBlock
  			ifFalse: [ exception signal ] ]
 ! !
 
+!Environment methodsFor: 'evaluating'!
+
+eval: aString on: aReceiver
+	| compiler |
+	compiler := Compiler new.
+	[ compiler parseExpression: aString ] on: Error do: [ :ex |
+		^ self alert: ex messageText ].
+	^ compiler evaluateExpression: aString on: aReceiver
+!
+
+interpret: aString inContext: anAIContext
+	"Similar to #eval:on:, with the following differences:
+	- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
+	- instead of evaluating against a receiver, evaluate in the context of `anAIContext`"
+
+	| compiler ast |
+	compiler := Compiler new.
+	[ ast := compiler parseExpression: aString ] on: Error do: [ :ex |
+		^ self alert: ex messageText ].
+	(SemanticAnalyzer on: anAIContext receiver class)
+		visit: ast.
+	^ anAIContext evaluateNode: ast
+! !
+
 !Environment methodsFor: 'services'!
 
 registerErrorHandler: anErrorHandler