Browse Source

- Fixes Helios debugger initialization
- Adds Halt class
- Adds Error >> signalerContext

Nicolas Petton 10 years ago
parent
commit
7cf59447ab

+ 7 - 11
src/Compiler-Interpreter.js

@@ -1141,7 +1141,7 @@ globals.ASTDebugger);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "flushInnerContexts",
-protocol: 'private',
+protocol: 'actions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -2460,7 +2460,7 @@ fn: function (aNode){
 var self=this;
 var sendIndex;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$4,$3,$6,$5,$7;
+var $1,$2,$4,$3,$5;
 $1=self._context();
 $2=self._selector();
 $ctx1.sendIdx["selector"]=1;
@@ -2469,23 +2469,19 @@ globals.ASTPCNodeVisitor.superclass.fn.prototype._visitSendNode_.apply(_st(self)
 $4=self._selector();
 $ctx1.sendIdx["selector"]=2;
 $3=_st($4).__eq(_st(aNode)._selector());
+$ctx1.sendIdx["="]=1;
 if(smalltalk.assert($3)){
-$6=self._index();
-$ctx1.sendIdx["index"]=1;
-$5=_st($6).__lt(sendIndex);
-if(! smalltalk.assert($5)){
-$7=_st(self._index()).__gt(sendIndex);
-if(! smalltalk.assert($7)){
+$5=_st(self._index()).__eq(sendIndex);
+if(smalltalk.assert($5)){
 self["@currentNode"]=aNode;
 self["@currentNode"];
 };
-};
 self._increaseIndex();
 };
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode,sendIndex:sendIndex},globals.ASTPCNodeVisitor)})},
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09| sendIndex |\x0a\x09sendIndex := self context sendIndexAt: self selector.\x0a\x09\x0a\x09super visitSendNode: aNode.\x0a\x09\x0a\x09self selector = aNode selector ifTrue: [\x0a\x09\x09self index < sendIndex ifFalse: [ \x0a\x09\x09\x09self index > sendIndex ifFalse: [ currentNode := aNode ] ].\x0a\x09\x09self increaseIndex ]",
-messageSends: ["sendIndexAt:", "context", "selector", "visitSendNode:", "ifTrue:", "=", "ifFalse:", "<", "index", ">", "increaseIndex"],
+source: "visitSendNode: aNode\x0a\x09| sendIndex |\x0a\x09sendIndex := self context sendIndexAt: self selector.\x0a\x09\x0a\x09super visitSendNode: aNode.\x0a\x09\x0a\x09self selector = aNode selector ifTrue: [\x0a\x09\x09self index = sendIndex ifTrue: [ currentNode := aNode ].\x0a\x09\x09self increaseIndex ]",
+messageSends: ["sendIndexAt:", "context", "selector", "visitSendNode:", "ifTrue:", "=", "index", "increaseIndex"],
 referencedClasses: []
 }),
 globals.ASTPCNodeVisitor);

+ 5 - 4
src/Compiler-Interpreter.st

@@ -406,7 +406,7 @@ result
 	^ result
 ! !
 
-!ASTDebugger methodsFor: 'private'!
+!ASTDebugger methodsFor: 'actions'!
 
 flushInnerContexts
 	"When stepping, the inner contexts are not relevent anymore,
@@ -414,7 +414,9 @@ flushInnerContexts
 	
 	self context ifNotNil: [ :cxt | 
 		cxt innerContext: nil ]
-!
+! !
+
+!ASTDebugger methodsFor: 'private'!
 
 onStep
 	"After each step, check if the interpreter is at the end,
@@ -859,8 +861,7 @@ visitSendNode: aNode
 	super visitSendNode: aNode.
 	
 	self selector = aNode selector ifTrue: [
-		self index < sendIndex ifFalse: [ 
-			self index > sendIndex ifFalse: [ currentNode := aNode ] ].
+		self index = sendIndex ifTrue: [ currentNode := aNode ].
 		self increaseIndex ]
 ! !
 

+ 7 - 5
src/Helios-Debugger.js

@@ -963,15 +963,17 @@ selector: "initializeFromError:",
 protocol: 'initialization',
 fn: function (anError){
 var self=this;
+var errorContext;
 function $AIContext(){return globals.AIContext||(typeof AIContext=="undefined"?nil:AIContext)}
 return smalltalk.withContext(function($ctx1) { 
 self["@error"]=anError;
-self["@rootContext"]=_st($AIContext())._fromMethodContext_(_st(self["@error"])._context());
-self._currentContext_(self["@rootContext"]);
-return self}, function($ctx1) {$ctx1.fill(self,"initializeFromError:",{anError:anError},globals.HLDebuggerModel)})},
+errorContext=_st($AIContext())._fromMethodContext_(_st(self["@error"])._context());
+self["@rootContext"]=_st(self["@error"])._signalerContextFrom_(errorContext);
+self._selectedMethod_(_st(self["@rootContext"])._method());
+return self}, function($ctx1) {$ctx1.fill(self,"initializeFromError:",{anError:anError,errorContext:errorContext},globals.HLDebuggerModel)})},
 args: ["anError"],
-source: "initializeFromError: anError\x0a\x09error := anError.\x0a\x09rootContext := (AIContext fromMethodContext: error context).\x0a\x09self currentContext: rootContext",
-messageSends: ["fromMethodContext:", "context", "currentContext:"],
+source: "initializeFromError: anError\x0a\x09| errorContext |\x0a\x09\x0a\x09error := anError.\x0a\x09errorContext := (AIContext fromMethodContext: error context).\x0a\x09rootContext := error signalerContextFrom: errorContext.\x0a\x09self selectedMethod: rootContext method",
+messageSends: ["fromMethodContext:", "context", "signalerContextFrom:", "selectedMethod:", "method"],
 referencedClasses: ["AIContext"]
 }),
 globals.HLDebuggerModel);

+ 5 - 2
src/Helios-Debugger.st

@@ -377,9 +377,12 @@ evaluate: aString
 !HLDebuggerModel methodsFor: 'initialization'!
 
 initializeFromError: anError
+	| errorContext |
+	
 	error := anError.
-	rootContext := (AIContext fromMethodContext: error context).
-	self currentContext: rootContext
+	errorContext := (AIContext fromMethodContext: error context).
+	rootContext := error signalerContextFrom: errorContext.
+	self selectedMethod: rootContext method
 ! !
 
 !HLDebuggerModel methodsFor: 'private'!

+ 99 - 0
src/Kernel-Exceptions.js

@@ -188,6 +188,53 @@ referencedClasses: []
 }),
 globals.Error);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "signalerContext",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._signalerContextFrom_(self._context());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"signalerContext",{},globals.Error)})},
+args: [],
+source: "signalerContext\x0a\x09^ self signalerContextFrom: self context",
+messageSends: ["signalerContextFrom:", "context"],
+referencedClasses: []
+}),
+globals.Error);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "signalerContextFrom:",
+protocol: 'accessing',
+fn: function (aContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $4,$3,$2,$1;
+$1=_st(aContext)._findContextSuchThat_((function(context){
+return smalltalk.withContext(function($ctx2) {
+$4=_st(context)._receiver();
+$ctx2.sendIdx["receiver"]=1;
+$3=_st($4).__eq_eq(self);
+$ctx2.sendIdx["=="]=1;
+$2=_st($3)._or_((function(){
+return smalltalk.withContext(function($ctx3) {
+return _st(_st(context)._receiver()).__eq_eq(self._class());
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+return _st($2)._not();
+}, function($ctx2) {$ctx2.fillBlock({context:context},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"signalerContextFrom:",{aContext:aContext},globals.Error)})},
+args: ["aContext"],
+source: "signalerContextFrom: aContext\x0a\x09\x22Find the first sender of signal(:), the first context which is neither \x0a\x09for an instance method nor for a class side method of Exception (or subclass).\x0a\x09This will make sure that the same context is found for both, `Error signal` \x0a\x09and `Error new signal`\x22\x0a\x0a\x09^ aContext findContextSuchThat: [ :context |\x0a\x09\x09(context receiver == self \x0a\x09\x09or: [ context receiver == self class ]) not ]",
+messageSends: ["findContextSuchThat:", "not", "or:", "==", "receiver", "class"],
+referencedClasses: []
+}),
+globals.Error);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "wasHandled",
@@ -257,6 +304,58 @@ referencedClasses: []
 globals.Error.klass);
 
 
+smalltalk.addClass('Halt', globals.Error, [], 'Kernel-Exceptions');
+globals.Halt.comment="I am provided to support `Object>>#halt`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "messageText",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Halt encountered";
+},
+args: [],
+source: "messageText\x0a\x09^ 'Halt encountered'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Halt);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "signalerContextFrom:",
+protocol: 'accessing',
+fn: function (aContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $4,$3,$2,$1;
+$1=_st(aContext)._findContextSuchThat_((function(context){
+return smalltalk.withContext(function($ctx2) {
+$4=_st(context)._receiver();
+$ctx2.sendIdx["receiver"]=1;
+$3=_st($4).__eq_eq(self);
+$ctx2.sendIdx["=="]=1;
+$2=_st($3)._or_((function(){
+return smalltalk.withContext(function($ctx3) {
+return _st(_st(_st(context)._receiver()).__eq_eq(self._class()))._or_((function(){
+return smalltalk.withContext(function($ctx4) {
+return _st(_st(_st(context)._method())._selector()).__eq("halt");
+}, function($ctx4) {$ctx4.fillBlock({},$ctx3,3)})}));
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+$ctx2.sendIdx["or:"]=1;
+return _st($2)._not();
+}, function($ctx2) {$ctx2.fillBlock({context:context},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"signalerContextFrom:",{aContext:aContext},globals.Halt)})},
+args: ["aContext"],
+source: "signalerContextFrom: aContext\x0a\x09\x22specialized version to find the proper context to open the debugger on.\x0a\x09This will find the first context whose method is no longer on `Halt` or \x0a\x09`Halt class` nor is `#halt` method itself.\x22\x0a\x09\x0a\x09^ aContext findContextSuchThat: [ :context |\x0a\x09\x09(context receiver == self \x0a\x09\x09or: [ (context receiver == self class) \x0a\x09\x09or: [ context method selector = #halt ]]) not ]",
+messageSends: ["findContextSuchThat:", "not", "or:", "==", "receiver", "class", "=", "selector", "method"],
+referencedClasses: []
+}),
+globals.Halt);
+
+
+
 smalltalk.addClass('JavaScriptException', globals.Error, ['exception'], 'Kernel-Exceptions');
 globals.JavaScriptException.comment="A JavaScriptException is thrown when a non-Smalltalk exception occurs while in the Smalltalk stack.\x0aSee `boot.js` `inContext()` and `BlockClosure >> on:do:`";
 smalltalk.addMethod(

+ 38 - 0
src/Kernel-Exceptions.st

@@ -34,6 +34,21 @@ messageText
 
 messageText: aString
 	messageText := aString
+!
+
+signalerContext
+	^ self signalerContextFrom: self context
+!
+
+signalerContextFrom: aContext
+	"Find the first sender of signal(:), the first context which is neither 
+	for an instance method nor for a class side method of Exception (or subclass).
+	This will make sure that the same context is found for both, `Error signal` 
+	and `Error new signal`"
+
+	^ aContext findContextSuchThat: [ :context |
+		(context receiver == self 
+		or: [ context receiver == self class ]) not ]
 ! !
 
 !Error methodsFor: 'initialization'!
@@ -93,6 +108,29 @@ signal: aString
 		signal: aString
 ! !
 
+Error subclass: #Halt
+	instanceVariableNames: ''
+	package: 'Kernel-Exceptions'!
+!Halt commentStamp!
+I am provided to support `Object>>#halt`.!
+
+!Halt methodsFor: 'accessing'!
+
+messageText
+	^ 'Halt encountered'
+!
+
+signalerContextFrom: aContext
+	"specialized version to find the proper context to open the debugger on.
+	This will find the first context whose method is no longer on `Halt` or 
+	`Halt class` nor is `#halt` method itself."
+	
+	^ aContext findContextSuchThat: [ :context |
+		(context receiver == self 
+		or: [ (context receiver == self class) 
+		or: [ context method selector = #halt ]]) not ]
+! !
+
 Error subclass: #JavaScriptException
 	instanceVariableNames: 'exception'
 	package: 'Kernel-Exceptions'!

+ 36 - 0
src/Kernel-Methods.js

@@ -1588,6 +1588,42 @@ referencedClasses: []
 }),
 globals.MethodContext);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "findContextSuchThat:",
+protocol: 'accessing',
+fn: function (testBlock){
+var self=this;
+var context;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+var $early={};
+try {
+context=self;
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(context)._isNil();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._whileFalse_((function(){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(testBlock)._value_(context);
+if(smalltalk.assert($1)){
+$2=context;
+throw $early=[$2];
+};
+context=_st(context)._outerContext();
+return context;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+return nil;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"findContextSuchThat:",{testBlock:testBlock,context:context},globals.MethodContext)})},
+args: ["testBlock"],
+source: "findContextSuchThat: testBlock\x0a\x09\x22Search self and my sender chain for first one that satisfies `testBlock`.  \x0a\x09Answer `nil` if none satisfy\x22\x0a\x0a\x09| context |\x0a\x09\x0a\x09context := self.\x0a\x09[ context isNil] whileFalse: [\x0a\x09\x09(testBlock value: context) \x0a\x09\x09\x09ifTrue: [ ^ context ].\x0a\x09\x09context := context outerContext ].\x0a\x0a\x09^ nil",
+messageSends: ["whileFalse:", "isNil", "ifTrue:", "value:", "outerContext"],
+referencedClasses: []
+}),
+globals.MethodContext);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "home",

+ 15 - 0
src/Kernel-Methods.st

@@ -570,6 +570,21 @@ evaluatedSelector
 	<return self.evaluatedSelector>
 !
 
+findContextSuchThat: testBlock
+	"Search self and my sender chain for first one that satisfies `testBlock`.  
+	Answer `nil` if none satisfy"
+
+	| context |
+	
+	context := self.
+	[ context isNil] whileFalse: [
+		(testBlock value: context) 
+			ifTrue: [ ^ context ].
+		context := context outerContext ].
+
+	^ nil
+!
+
 home
 	<return self.homeContext>
 !

+ 5 - 4
src/Kernel-Objects.js

@@ -660,13 +660,14 @@ selector: "halt",
 protocol: 'error handling',
 fn: function (){
 var self=this;
+function $Halt(){return globals.Halt||(typeof Halt=="undefined"?nil:Halt)}
 return smalltalk.withContext(function($ctx1) { 
-self._error_("Halt encountered");
+_st($Halt())._signal();
 return self}, function($ctx1) {$ctx1.fill(self,"halt",{},globals.Object)})},
 args: [],
-source: "halt\x0a\x09self error: 'Halt encountered'",
-messageSends: ["error:"],
-referencedClasses: []
+source: "halt\x0a\x09Halt signal",
+messageSends: ["signal"],
+referencedClasses: ["Halt"]
 }),
 globals.Object);
 

+ 1 - 1
src/Kernel-Objects.st

@@ -263,7 +263,7 @@ error: aString
 !
 
 halt
-	self error: 'Halt encountered'
+	Halt signal
 !
 
 shouldNotImplement