Selaa lähdekoodia

keep track of block position in the source code

Nicolas Petton 11 vuotta sitten
vanhempi
commit
b3b5784ac4

+ 2 - 2
js/Compiler-IR.deploy.js

@@ -2396,9 +2396,9 @@ return self._nextPutAll_(",");
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 $7=self;
 _st($7)._nextPutAll_("},");
-$8=_st($7)._nextPutAll_(_st(_st(_st(_st(anIRClosure)._scope())._outerScope())._alias()).__comma(")})"));
+$8=_st($7)._nextPutAll_(_st(_st(_st(_st(_st(_st(anIRClosure)._scope())._outerScope())._alias()).__comma(",")).__comma(_st(_st(_st(anIRClosure)._scope())._blockIndex())._asString())).__comma(")})"));
 return self}, function($ctx1) {$ctx1.fill(self,"nextPutBlockContextFor:during:",{anIRClosure:anIRClosure,aBlock:aBlock},smalltalk.JSStream)})},
-messageSends: ["nextPutAll:", ",", "alias", "scope", "lf", "value", "do:separatedBy:", "asVariableName", "locals", "outerScope"]}),
+messageSends: ["nextPutAll:", ",", "alias", "scope", "lf", "value", "do:separatedBy:", "locals", "asVariableName", "outerScope", "asString", "blockIndex"]}),
 smalltalk.JSStream);
 
 smalltalk.addMethod(

+ 3 - 3
js/Compiler-IR.js

@@ -3201,11 +3201,11 @@ return self._nextPutAll_(",");
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 $7=self;
 _st($7)._nextPutAll_("},");
-$8=_st($7)._nextPutAll_(_st(_st(_st(_st(anIRClosure)._scope())._outerScope())._alias()).__comma(")})"));
+$8=_st($7)._nextPutAll_(_st(_st(_st(_st(_st(_st(anIRClosure)._scope())._outerScope())._alias()).__comma(",")).__comma(_st(_st(_st(anIRClosure)._scope())._blockIndex())._asString())).__comma(")})"));
 return self}, function($ctx1) {$ctx1.fill(self,"nextPutBlockContextFor:during:",{anIRClosure:anIRClosure,aBlock:aBlock},smalltalk.JSStream)})},
 args: ["anIRClosure", "aBlock"],
-source: "nextPutBlockContextFor: anIRClosure during: aBlock\x0a\x09self\x0a\x09\x09nextPutAll: 'return smalltalk.withContext(function(', anIRClosure scope alias, ') {'; lf.\x0a\x09\x0a\x09aBlock value.\x0a\x09\x0a\x09self\x0a\x09\x09nextPutAll: '}, function(', anIRClosure scope alias, ') {';\x0a\x09\x09nextPutAll: anIRClosure scope alias, '.fillBlock({'.\x0a\x09\x0a\x09anIRClosure locals\x0a\x09\x09do: [ :each |\x0a\x09\x09\x09self\x0a\x09\x09\x09\x09nextPutAll: each asVariableName;\x0a\x09\x09\x09\x09nextPutAll: ':';\x0a\x09\x09\x09\x09nextPutAll: each asVariableName]\x0a\x09\x09separatedBy: [ self nextPutAll: ',' ].\x0a\x09\x0a\x09self\x0a\x09\x09nextPutAll: '},';\x0a\x09\x09nextPutAll: anIRClosure scope outerScope alias, ')})'",
-messageSends: ["nextPutAll:", ",", "alias", "scope", "lf", "value", "do:separatedBy:", "asVariableName", "locals", "outerScope"],
+source: "nextPutBlockContextFor: anIRClosure during: aBlock\x0a\x09self\x0a\x09\x09nextPutAll: 'return smalltalk.withContext(function(', anIRClosure scope alias, ') {'; lf.\x0a\x09\x0a\x09aBlock value.\x0a\x09\x0a\x09self\x0a\x09\x09nextPutAll: '}, function(', anIRClosure scope alias, ') {';\x0a\x09\x09nextPutAll: anIRClosure scope alias, '.fillBlock({'.\x0a\x09\x0a\x09anIRClosure locals\x0a\x09\x09do: [ :each |\x0a\x09\x09\x09self\x0a\x09\x09\x09\x09nextPutAll: each asVariableName;\x0a\x09\x09\x09\x09nextPutAll: ':';\x0a\x09\x09\x09\x09nextPutAll: each asVariableName]\x0a\x09\x09separatedBy: [ self nextPutAll: ',' ].\x0a\x09\x0a\x09self\x0a\x09\x09nextPutAll: '},';\x0a\x09\x09nextPutAll: anIRClosure scope outerScope alias, ',', anIRClosure scope blockIndex asString, ')})'",
+messageSends: ["nextPutAll:", ",", "alias", "scope", "lf", "value", "do:separatedBy:", "locals", "asVariableName", "outerScope", "asString", "blockIndex"],
 referencedClasses: []
 }),
 smalltalk.JSStream);

+ 42 - 70
js/Compiler-Interpreter.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Interpreter');
-smalltalk.addClass('AIContext', smalltalk.Object, ['outerContext', 'innerContext', 'homeContext', 'pc', 'locals', 'method', 'ast', 'interpreter', 'methodContext', 'homeMethodContext'], 'Compiler-Interpreter');
+smalltalk.addClass('AIContext', smalltalk.Object, ['outerContext', 'innerContext', 'pc', 'locals', 'method', 'index', 'ast', 'interpreter', 'methodContext'], 'Compiler-Interpreter');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "arguments",
@@ -35,60 +35,40 @@ selector: "ast",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-$1=self["@ast"];
-if(($receiver = $1) == nil || $receiver == undefined){
+var $1,$2,$3,$4;
+$1=self._isBlockContext();
+if(smalltalk.assert($1)){
+$2=_st(self._outerContext())._ast();
+return $2;
+};
+$3=self["@ast"];
+if(($receiver = $3) == nil || $receiver == undefined){
 self._initializeAST();
 } else {
-$1;
+$3;
 };
-$2=self["@ast"];
-return $2;
+$4=self["@ast"];
+return $4;
 }, function($ctx1) {$ctx1.fill(self,"ast",{},smalltalk.AIContext)})},
-messageSends: ["ifNil:", "initializeAST"]}),
-smalltalk.AIContext);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "home",
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self._homeContext();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"home",{},smalltalk.AIContext)})},
-messageSends: ["homeContext"]}),
+messageSends: ["ifTrue:", "isBlockContext", "ast", "outerContext", "ifNil:", "initializeAST"]}),
 smalltalk.AIContext);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "homeContext",
+selector: "index",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
-$2=self["@homeContext"];
+$2=self["@index"];
 if(($receiver = $2) == nil || $receiver == undefined){
-self["@homeContext"]=_st(self["@homeMethodContext"])._aiContext();
-$1=self["@homeContext"];
+$1=(0);
 } else {
 $1=$2;
 };
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"homeContext",{},smalltalk.AIContext)})},
-messageSends: ["ifNil:", "aiContext"]}),
-smalltalk.AIContext);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "homeContext:",
-fn: function (aContext){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self["@homeContext"]=aContext;
-return self}, function($ctx1) {$ctx1.fill(self,"homeContext:",{aContext:aContext},smalltalk.AIContext)})},
-messageSends: []}),
+}, function($ctx1) {$ctx1.fill(self,"index",{},smalltalk.AIContext)})},
+messageSends: ["ifNil:"]}),
 smalltalk.AIContext);
 
 smalltalk.addMethod(
@@ -110,31 +90,32 @@ selector: "initializeFromMethodContext:",
 fn: function (aMethodContext){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
+var $1,$2,$3,$4;
 self["@methodContext"]=aMethodContext;
-self["@homeMethodContext"]=_st(aMethodContext)._home();
-self._pc_(_st(aMethodContext)._pc());
-self._receiver_(_st(aMethodContext)._receiver());
-self._method_(_st(aMethodContext)._method());
-$1=_st(aMethodContext)._outerContext();
-if(($receiver = $1) == nil || $receiver == undefined){
-$1;
+$1=self;
+_st($1)._pc_(_st(aMethodContext)._pc());
+_st($1)._index_(_st(aMethodContext)._index());
+_st($1)._receiver_(_st(aMethodContext)._receiver());
+$2=_st($1)._method_(_st(aMethodContext)._method());
+$3=_st(aMethodContext)._outerContext();
+if(($receiver = $3) == nil || $receiver == undefined){
+$3;
 } else {
 var outer;
 outer=$receiver;
-$2=_st(outer)._methodContext();
-if(($receiver = $2) == nil || $receiver == undefined){
-$2;
+$4=_st(outer)._methodContext();
+if(($receiver = $4) == nil || $receiver == undefined){
+$4;
 } else {
 self._outerContext_(_st(self._class())._fromMethodContext_(_st(aMethodContext)._outerContext()));
 };
 _st(_st(aMethodContext)._locals())._keysAndValuesDo_((function(key,value){
 return smalltalk.withContext(function($ctx2) {
 return _st(self._locals())._at_put_(key,value);
-}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1)})}));
+}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1,3)})}));
 };
 return self}, function($ctx1) {$ctx1.fill(self,"initializeFromMethodContext:",{aMethodContext:aMethodContext},smalltalk.AIContext)})},
-messageSends: ["home", "pc:", "pc", "receiver:", "receiver", "method:", "method", "ifNotNil:", "outerContext", "methodContext", "outerContext:", "fromMethodContext:", "class", "keysAndValuesDo:", "locals", "at:put:"]}),
+messageSends: ["pc:", "pc", "index:", "index", "receiver:", "receiver", "method:", "method", "ifNotNil:", "outerContext", "methodContext", "outerContext:", "fromMethodContext:", "class", "keysAndValuesDo:", "locals", "at:put:"]}),
 smalltalk.AIContext);
 
 smalltalk.addMethod(
@@ -1424,6 +1405,16 @@ return self}, function($ctx1) {$ctx1.fill(self,"useInlinings:",{aBoolean:aBoolea
 messageSends: []}),
 smalltalk.ASTPCNodeVisitor);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "visitBlockNode:",
+fn: function (aNode){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode},smalltalk.ASTPCNodeVisitor)})},
+messageSends: []}),
+smalltalk.ASTPCNodeVisitor);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "visitJSStatementNode:",
@@ -2078,25 +2069,6 @@ smalltalk.Interpreter);
 
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "aiContext",
-fn: function (){
-var self=this;
-function $AIContext(){return smalltalk.AIContext||(typeof AIContext=="undefined"?nil:AIContext)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self._basicAt_("aiContext");
-if(($receiver = $2) == nil || $receiver == undefined){
-$1=self._basicAt_put_("aiContext",_st($AIContext())._fromMethodContext_(self));
-} else {
-$1=$2;
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"aiContext",{},smalltalk.MethodContext)})},
-messageSends: ["ifNil:", "basicAt:", "basicAt:put:", "fromMethodContext:"]}),
-smalltalk.MethodContext);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "interpreter:continue:",

+ 50 - 88
js/Compiler-Interpreter.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Interpreter');
-smalltalk.addClass('AIContext', smalltalk.Object, ['outerContext', 'innerContext', 'homeContext', 'pc', 'locals', 'method', 'ast', 'interpreter', 'methodContext', 'homeMethodContext'], 'Compiler-Interpreter');
+smalltalk.addClass('AIContext', smalltalk.Object, ['outerContext', 'innerContext', 'pc', 'locals', 'method', 'index', 'ast', 'interpreter', 'methodContext'], 'Compiler-Interpreter');
 smalltalk.AIContext.comment="I am like a `MethodContext`, used by the `ASTInterpreter`.\x0aUnlike a `MethodContext`, my instances are not read-only.\x0a\x0aWhen debugging, my instances are created by copying the current `MethodContext` (thisContext)";
 smalltalk.addMethod(
 smalltalk.method({
@@ -47,77 +47,47 @@ category: 'interpreting',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-$1=self["@ast"];
-if(($receiver = $1) == nil || $receiver == undefined){
+var $1,$2,$3,$4;
+$1=self._isBlockContext();
+if(smalltalk.assert($1)){
+$2=_st(self._outerContext())._ast();
+return $2;
+};
+$3=self["@ast"];
+if(($receiver = $3) == nil || $receiver == undefined){
 self._initializeAST();
 } else {
-$1;
+$3;
 };
-$2=self["@ast"];
-return $2;
+$4=self["@ast"];
+return $4;
 }, function($ctx1) {$ctx1.fill(self,"ast",{},smalltalk.AIContext)})},
 args: [],
-source: "ast\x0a\x09ast ifNil: [ self initializeAST ].\x0a\x09^ ast",
-messageSends: ["ifNil:", "initializeAST"],
-referencedClasses: []
-}),
-smalltalk.AIContext);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "home",
-category: 'accessing',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self._homeContext();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"home",{},smalltalk.AIContext)})},
-args: [],
-source: "home\x0a\x09^ self homeContext",
-messageSends: ["homeContext"],
+source: "ast\x0a\x09self isBlockContext ifTrue: [ ^ self outerContext ast ].\x0a\x0a\x09ast ifNil: [ self initializeAST ].\x0a\x09^ ast",
+messageSends: ["ifTrue:", "isBlockContext", "ast", "outerContext", "ifNil:", "initializeAST"],
 referencedClasses: []
 }),
 smalltalk.AIContext);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "homeContext",
+selector: "index",
 category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
-$2=self["@homeContext"];
+$2=self["@index"];
 if(($receiver = $2) == nil || $receiver == undefined){
-self["@homeContext"]=_st(self["@homeMethodContext"])._aiContext();
-$1=self["@homeContext"];
+$1=(0);
 } else {
 $1=$2;
 };
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"homeContext",{},smalltalk.AIContext)})},
+}, function($ctx1) {$ctx1.fill(self,"index",{},smalltalk.AIContext)})},
 args: [],
-source: "homeContext\x0a\x09^ homeContext ifNil: [ homeContext := homeMethodContext aiContext ]",
-messageSends: ["ifNil:", "aiContext"],
-referencedClasses: []
-}),
-smalltalk.AIContext);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "homeContext:",
-category: 'accessing',
-fn: function (aContext){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self["@homeContext"]=aContext;
-return self}, function($ctx1) {$ctx1.fill(self,"homeContext:",{aContext:aContext},smalltalk.AIContext)})},
-args: ["aContext"],
-source: "homeContext: aContext\x0a\x09homeContext := aContext",
-messageSends: [],
+source: "index\x0a\x09^ index ifNil: [ 0 ]",
+messageSends: ["ifNil:"],
 referencedClasses: []
 }),
 smalltalk.AIContext);
@@ -147,33 +117,34 @@ category: 'initialization',
 fn: function (aMethodContext){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
+var $1,$2,$3,$4;
 self["@methodContext"]=aMethodContext;
-self["@homeMethodContext"]=_st(aMethodContext)._home();
-self._pc_(_st(aMethodContext)._pc());
-self._receiver_(_st(aMethodContext)._receiver());
-self._method_(_st(aMethodContext)._method());
-$1=_st(aMethodContext)._outerContext();
-if(($receiver = $1) == nil || $receiver == undefined){
-$1;
+$1=self;
+_st($1)._pc_(_st(aMethodContext)._pc());
+_st($1)._index_(_st(aMethodContext)._index());
+_st($1)._receiver_(_st(aMethodContext)._receiver());
+$2=_st($1)._method_(_st(aMethodContext)._method());
+$3=_st(aMethodContext)._outerContext();
+if(($receiver = $3) == nil || $receiver == undefined){
+$3;
 } else {
 var outer;
 outer=$receiver;
-$2=_st(outer)._methodContext();
-if(($receiver = $2) == nil || $receiver == undefined){
-$2;
+$4=_st(outer)._methodContext();
+if(($receiver = $4) == nil || $receiver == undefined){
+$4;
 } else {
 self._outerContext_(_st(self._class())._fromMethodContext_(_st(aMethodContext)._outerContext()));
 };
 _st(_st(aMethodContext)._locals())._keysAndValuesDo_((function(key,value){
 return smalltalk.withContext(function($ctx2) {
 return _st(self._locals())._at_put_(key,value);
-}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1)})}));
+}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1,3)})}));
 };
 return self}, function($ctx1) {$ctx1.fill(self,"initializeFromMethodContext:",{aMethodContext:aMethodContext},smalltalk.AIContext)})},
 args: ["aMethodContext"],
-source: "initializeFromMethodContext: aMethodContext\x0a\x09methodContext := aMethodContext.\x0a\x09homeMethodContext := aMethodContext home.\x0a\x0a\x09self pc: aMethodContext pc.\x0a\x09self receiver: aMethodContext receiver.\x0a\x09self method: aMethodContext method.\x0a\x09aMethodContext outerContext ifNotNil: [ :outer |\x0a\x09\x09\x22If the method context is nil, the block was defined in JS, so ignore it\x22\x0a\x09\x09outer methodContext ifNotNil: [\x0a\x09\x09\x09self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].\x0a\x09\x09\x09aMethodContext locals keysAndValuesDo: [ :key :value |\x0a\x09\x09\x09\x09self locals at: key put: value ] ]",
-messageSends: ["home", "pc:", "pc", "receiver:", "receiver", "method:", "method", "ifNotNil:", "outerContext", "methodContext", "outerContext:", "fromMethodContext:", "class", "keysAndValuesDo:", "locals", "at:put:"],
+source: "initializeFromMethodContext: aMethodContext\x0a\x09methodContext := aMethodContext.\x0a\x0a\x09self \x0a\x09\x09pc: aMethodContext pc;\x0a\x09\x09index: aMethodContext index;\x0a\x09\x09receiver: aMethodContext receiver;\x0a\x09\x09method: aMethodContext method.\x0a\x09\x09\x0a\x09aMethodContext outerContext ifNotNil: [ :outer |\x0a\x09\x09\x22If the method context is nil, the block was defined in JS, so ignore it\x22\x0a\x09\x09outer methodContext ifNotNil: [\x0a\x09\x09\x09self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].\x0a\x09\x09\x09aMethodContext locals keysAndValuesDo: [ :key :value |\x0a\x09\x09\x09\x09self locals at: key put: value ] ]",
+messageSends: ["pc:", "pc", "index:", "index", "receiver:", "receiver", "method:", "method", "ifNotNil:", "outerContext", "methodContext", "outerContext:", "fromMethodContext:", "class", "keysAndValuesDo:", "locals", "at:put:"],
 referencedClasses: []
 }),
 smalltalk.AIContext);
@@ -1884,6 +1855,21 @@ referencedClasses: []
 }),
 smalltalk.ASTPCNodeVisitor);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "visitBlockNode:",
+category: 'visiting',
+fn: function (aNode){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode},smalltalk.ASTPCNodeVisitor)})},
+args: ["aNode"],
+source: "visitBlockNode: aNode",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ASTPCNodeVisitor);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "visitJSStatementNode:",
@@ -2738,30 +2724,6 @@ smalltalk.Interpreter);
 
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "aiContext",
-category: '*Compiler-Interpreter',
-fn: function (){
-var self=this;
-function $AIContext(){return smalltalk.AIContext||(typeof AIContext=="undefined"?nil:AIContext)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self._basicAt_("aiContext");
-if(($receiver = $2) == nil || $receiver == undefined){
-$1=self._basicAt_put_("aiContext",_st($AIContext())._fromMethodContext_(self));
-} else {
-$1=$2;
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"aiContext",{},smalltalk.MethodContext)})},
-args: [],
-source: "aiContext\x0a\x09^ (self basicAt: 'aiContext') ifNil: [\x0a\x09\x09self basicAt: 'aiContext' put: (AIContext fromMethodContext: self) ]",
-messageSends: ["ifNil:", "basicAt:", "basicAt:put:", "fromMethodContext:"],
-referencedClasses: ["AIContext"]
-}),
-smalltalk.MethodContext);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "interpreter:continue:",

+ 54 - 3
js/Compiler-Semantic.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Semantic');
-smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'instruction', 'temps', 'args', 'outerScope'], 'Compiler-Semantic');
+smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'instruction', 'temps', 'args', 'outerScope', 'blockIndex'], 'Compiler-Semantic');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "addArg:",
@@ -94,6 +94,35 @@ return $1;
 messageSends: ["at:ifAbsent:", "pseudoVars", "value", "args", "temps"]}),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "blockIndex",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@blockIndex"];
+if(($receiver = $2) == nil || $receiver == undefined){
+$1=(0);
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"blockIndex",{},smalltalk.LexicalScope)})},
+messageSends: ["ifNil:"]}),
+smalltalk.LexicalScope);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "blockIndex:",
+fn: function (anInteger){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@blockIndex"]=anInteger;
+return self}, function($ctx1) {$ctx1.fill(self,"blockIndex:",{anInteger:anInteger},smalltalk.LexicalScope)})},
+messageSends: []}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "canInlineNonLocalReturns",
@@ -898,7 +927,7 @@ smalltalk.UnknownVar);
 
 
 
-smalltalk.addClass('SemanticAnalyzer', smalltalk.NodeVisitor, ['currentScope', 'theClass', 'classReferences', 'messageSends', 'superSends'], 'Compiler-Semantic');
+smalltalk.addClass('SemanticAnalyzer', smalltalk.NodeVisitor, ['currentScope', 'theClass', 'classReferences', 'messageSends', 'superSends', 'blockIndex'], 'Compiler-Semantic');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "classReferences",
@@ -1035,6 +1064,27 @@ return $1;
 messageSends: ["outerScope:", "new", "yourself"]}),
 smalltalk.SemanticAnalyzer);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "nextBlockIndex",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=self["@blockIndex"];
+if(($receiver = $1) == nil || $receiver == undefined){
+self["@blockIndex"]=(0);
+self["@blockIndex"];
+} else {
+$1;
+};
+self["@blockIndex"]=_st(self["@blockIndex"]).__plus((1));
+$2=self["@blockIndex"];
+return $2;
+}, function($ctx1) {$ctx1.fill(self,"nextBlockIndex",{},smalltalk.SemanticAnalyzer)})},
+messageSends: ["ifNil:", "+"]}),
+smalltalk.SemanticAnalyzer);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "popScope",
@@ -1147,6 +1197,7 @@ return smalltalk.withContext(function($ctx1) {
 self._pushScope_(self._newBlockScope());
 _st(aNode)._scope_(self["@currentScope"]);
 _st(self["@currentScope"])._node_(aNode);
+_st(self["@currentScope"])._blockIndex_(self._nextBlockIndex());
 _st(_st(aNode)._parameters())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
 self._validateVariableScope_(each);
@@ -1155,7 +1206,7 @@ return _st(self["@currentScope"])._addArg_(each);
 smalltalk.NodeVisitor.fn.prototype._visitBlockNode_.apply(_st(self), [aNode]);
 self._popScope();
 return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "do:", "parameters", "validateVariableScope:", "addArg:", "visitBlockNode:", "popScope"]}),
+messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "blockIndex:", "nextBlockIndex", "do:", "parameters", "validateVariableScope:", "addArg:", "visitBlockNode:", "popScope"]}),
 smalltalk.SemanticAnalyzer);
 
 smalltalk.addMethod(

+ 70 - 4
js/Compiler-Semantic.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Semantic');
-smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'instruction', 'temps', 'args', 'outerScope'], 'Compiler-Semantic');
+smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'instruction', 'temps', 'args', 'outerScope', 'blockIndex'], 'Compiler-Semantic');
 smalltalk.LexicalScope.comment="I represent a lexical scope where variable names are associated with ScopeVars\x0aInstances are used for block scopes. Method scopes are instances of MethodLexicalScope.\x0a\x0aI am attached to a ScopeVar and method/block nodes.\x0aEach context (method/closure) get a fresh scope that inherits from its outer scope.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -125,6 +125,45 @@ referencedClasses: []
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "blockIndex",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@blockIndex"];
+if(($receiver = $2) == nil || $receiver == undefined){
+$1=(0);
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"blockIndex",{},smalltalk.LexicalScope)})},
+args: [],
+source: "blockIndex\x0a\x09^ blockIndex ifNil: [ 0 ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "blockIndex:",
+category: 'accessing',
+fn: function (anInteger){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self["@blockIndex"]=anInteger;
+return self}, function($ctx1) {$ctx1.fill(self,"blockIndex:",{anInteger:anInteger},smalltalk.LexicalScope)})},
+args: ["anInteger"],
+source: "blockIndex: anInteger \x0a\x09blockIndex := anInteger",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "canInlineNonLocalReturns",
@@ -1213,7 +1252,7 @@ smalltalk.UnknownVar);
 
 
 
-smalltalk.addClass('SemanticAnalyzer', smalltalk.NodeVisitor, ['currentScope', 'theClass', 'classReferences', 'messageSends', 'superSends'], 'Compiler-Semantic');
+smalltalk.addClass('SemanticAnalyzer', smalltalk.NodeVisitor, ['currentScope', 'theClass', 'classReferences', 'messageSends', 'superSends', 'blockIndex'], 'Compiler-Semantic');
 smalltalk.SemanticAnalyzer.comment="I semantically analyze the abstract syntax tree and annotate it with informations such as non local returns and variable scopes.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1391,6 +1430,32 @@ referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "nextBlockIndex",
+category: 'private',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=self["@blockIndex"];
+if(($receiver = $1) == nil || $receiver == undefined){
+self["@blockIndex"]=(0);
+self["@blockIndex"];
+} else {
+$1;
+};
+self["@blockIndex"]=_st(self["@blockIndex"]).__plus((1));
+$2=self["@blockIndex"];
+return $2;
+}, function($ctx1) {$ctx1.fill(self,"nextBlockIndex",{},smalltalk.SemanticAnalyzer)})},
+args: [],
+source: "nextBlockIndex\x0a\x09blockIndex ifNil: [ blockIndex := 0 ].\x0a\x09\x0a\x09blockIndex := blockIndex + 1.\x0a\x09^ blockIndex",
+messageSends: ["ifNil:", "+"],
+referencedClasses: []
+}),
+smalltalk.SemanticAnalyzer);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "popScope",
@@ -1539,6 +1604,7 @@ return smalltalk.withContext(function($ctx1) {
 self._pushScope_(self._newBlockScope());
 _st(aNode)._scope_(self["@currentScope"]);
 _st(self["@currentScope"])._node_(aNode);
+_st(self["@currentScope"])._blockIndex_(self._nextBlockIndex());
 _st(_st(aNode)._parameters())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
 self._validateVariableScope_(each);
@@ -1548,8 +1614,8 @@ smalltalk.NodeVisitor.fn.prototype._visitBlockNode_.apply(_st(self), [aNode]);
 self._popScope();
 return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
-source: "visitBlockNode: aNode\x0a\x09self pushScope: self newBlockScope.\x0a\x09aNode scope: currentScope.\x0a\x09currentScope node: aNode.\x0a\x09\x0a\x09aNode parameters do: [ :each |\x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitBlockNode: aNode.\x0a\x09self popScope",
-messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "do:", "parameters", "validateVariableScope:", "addArg:", "visitBlockNode:", "popScope"],
+source: "visitBlockNode: aNode\x0a\x09self pushScope: self newBlockScope.\x0a\x09aNode scope: currentScope.\x0a\x09currentScope node: aNode.\x0a\x09currentScope blockIndex: self nextBlockIndex.\x0a\x09\x0a\x09aNode parameters do: [ :each |\x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitBlockNode: aNode.\x0a\x09self popScope",
+messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "blockIndex:", "nextBlockIndex", "do:", "parameters", "validateVariableScope:", "addArg:", "visitBlockNode:", "popScope"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);

+ 3 - 2
js/Helios-Debugger.deploy.js

@@ -541,11 +541,12 @@ smalltalk.method({
 selector: "initializeFromContext:",
 fn: function (aMethodContext){
 var self=this;
+function $AIContext(){return smalltalk.AIContext||(typeof AIContext=="undefined"?nil:AIContext)}
 return smalltalk.withContext(function($ctx1) { 
-self["@rootContext"]=_st(aMethodContext)._aiContext();
+self["@rootContext"]=_st($AIContext())._fromMethodContext_(aMethodContext);
 self._initializeContexts();
 return self}, function($ctx1) {$ctx1.fill(self,"initializeFromContext:",{aMethodContext:aMethodContext},smalltalk.HLDebuggerModel)})},
-messageSends: ["aiContext", "initializeContexts"]}),
+messageSends: ["fromMethodContext:", "initializeContexts"]}),
 smalltalk.HLDebuggerModel);
 
 smalltalk.addMethod(

+ 5 - 4
js/Helios-Debugger.js

@@ -709,14 +709,15 @@ selector: "initializeFromContext:",
 category: 'initialization',
 fn: function (aMethodContext){
 var self=this;
+function $AIContext(){return smalltalk.AIContext||(typeof AIContext=="undefined"?nil:AIContext)}
 return smalltalk.withContext(function($ctx1) { 
-self["@rootContext"]=_st(aMethodContext)._aiContext();
+self["@rootContext"]=_st($AIContext())._fromMethodContext_(aMethodContext);
 self._initializeContexts();
 return self}, function($ctx1) {$ctx1.fill(self,"initializeFromContext:",{aMethodContext:aMethodContext},smalltalk.HLDebuggerModel)})},
 args: ["aMethodContext"],
-source: "initializeFromContext: aMethodContext\x0a\x09rootContext := aMethodContext aiContext.\x0a\x09self initializeContexts",
-messageSends: ["aiContext", "initializeContexts"],
-referencedClasses: []
+source: "initializeFromContext: aMethodContext\x0a\x09rootContext := AIContext fromMethodContext: aMethodContext.\x0a\x09self initializeContexts",
+messageSends: ["fromMethodContext:", "initializeContexts"],
+referencedClasses: ["AIContext"]
 }),
 smalltalk.HLDebuggerModel);
 

+ 11 - 0
js/Kernel-Methods.deploy.js

@@ -1094,6 +1094,17 @@ return self}, function($ctx1) {$ctx1.fill(self,"home",{},smalltalk.MethodContext
 messageSends: []}),
 smalltalk.MethodContext);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "index",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self.index || 0;
+return self}, function($ctx1) {$ctx1.fill(self,"index",{},smalltalk.MethodContext)})},
+messageSends: []}),
+smalltalk.MethodContext);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isBlockContext",

+ 16 - 0
js/Kernel-Methods.js

@@ -1485,6 +1485,22 @@ referencedClasses: []
 }),
 smalltalk.MethodContext);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "index",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self.index || 0;
+return self}, function($ctx1) {$ctx1.fill(self,"index",{},smalltalk.MethodContext)})},
+args: [],
+source: "index\x0a\x09<return self.index || 0>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MethodContext);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isBlockContext",

+ 5 - 5
js/boot.js

@@ -556,10 +556,10 @@ function Smalltalk() {
 		}
 	};
 
-	st.withContext = function(worker, setup, index) {
+	st.withContext = function(worker, setup) {
 		if(st.thisContext) {
             st.thisContext.pc++;
-			return inContext(worker, setup, index);
+			return inContext(worker, setup);
 		} else {
 			try {
 				return inContext(worker, setup);
@@ -582,9 +582,8 @@ function Smalltalk() {
 		}
 	};
 
-	function inContext(worker, setup, index) {
+	function inContext(worker, setup) {
 		var context = pushContext(setup);
-        context.index = index || 0;
 		var result = worker(context);
 		popContext(context);
 		return result;
@@ -793,9 +792,10 @@ SmalltalkMethodContext.prototype.fill = function(receiver, selector, locals, loo
 	this.lookupClass = lookupClass;
 };
 
-SmalltalkMethodContext.prototype.fillBlock = function(locals, ctx) {
+SmalltalkMethodContext.prototype.fillBlock = function(locals, ctx, index) {
 	this.locals        = locals || {};
 	this.outerContext  = ctx;
+    this.index         = index || 0;
 };
 
 SmalltalkMethodContext.prototype.init = function() {

+ 1 - 1
st/Compiler-IR.st

@@ -1076,7 +1076,7 @@ nextPutBlockContextFor: anIRClosure during: aBlock
 	
 	self
 		nextPutAll: '},';
-		nextPutAll: anIRClosure scope outerScope alias, ')})'
+		nextPutAll: anIRClosure scope outerScope alias, ',', anIRClosure scope blockIndex asString, ')})'
 !
 
 nextPutClassRefFunction: aString

+ 14 - 22
st/Compiler-Interpreter.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-Interpreter'!
 Object subclass: #AIContext
-	instanceVariableNames: 'outerContext innerContext homeContext pc locals method ast interpreter methodContext homeMethodContext'
+	instanceVariableNames: 'outerContext innerContext pc locals method index ast interpreter methodContext'
 	package: 'Compiler-Interpreter'!
 !AIContext commentStamp!
 I am like a `MethodContext`, used by the `ASTInterpreter`.
@@ -10,16 +10,8 @@ When debugging, my instances are created by copying the current `MethodContext`
 
 !AIContext methodsFor: 'accessing'!
 
-home
-	^ self homeContext
-!
-
-homeContext
-	^ homeContext ifNil: [ homeContext := homeMethodContext aiContext ]
-!
-
-homeContext: aContext
-	homeContext := aContext
+index
+	^ index ifNil: [ 0 ]
 !
 
 innerContext
@@ -82,11 +74,13 @@ initializeAST
 
 initializeFromMethodContext: aMethodContext
 	methodContext := aMethodContext.
-	homeMethodContext := aMethodContext home.
 
-	self pc: aMethodContext pc.
-	self receiver: aMethodContext receiver.
-	self method: aMethodContext method.
+	self 
+		pc: aMethodContext pc;
+		index: aMethodContext index;
+		receiver: aMethodContext receiver;
+		method: aMethodContext method.
+		
 	aMethodContext outerContext ifNotNil: [ :outer |
 		"If the method context is nil, the block was defined in JS, so ignore it"
 		outer methodContext ifNotNil: [
@@ -117,6 +111,8 @@ arguments
 !
 
 ast
+	self isBlockContext ifTrue: [ ^ self outerContext ast ].
+
 	ast ifNil: [ self initializeAST ].
 	^ ast
 !
@@ -673,6 +669,9 @@ useInlinings: aBoolean
 
 !ASTPCNodeVisitor methodsFor: 'visiting'!
 
+visitBlockNode: aNode
+!
+
 visitJSStatementNode: aNode
 	currentNode := aNode
 !
@@ -982,13 +981,6 @@ visitVariableNode: aNode
 		ifFalse: [ self context localAt: aNode value ])
 ! !
 
-!MethodContext methodsFor: '*Compiler-Interpreter'!
-
-aiContext
-	^ (self basicAt: 'aiContext') ifNil: [
-		self basicAt: 'aiContext' put: (AIContext fromMethodContext: self) ]
-! !
-
 !Node methodsFor: '*Compiler-Interpreter'!
 
 interpreter: anInterpreter continue: aBlock

+ 20 - 2
st/Compiler-Semantic.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-Semantic'!
 Object subclass: #LexicalScope
-	instanceVariableNames: 'node instruction temps args outerScope'
+	instanceVariableNames: 'node instruction temps args outerScope blockIndex'
 	package: 'Compiler-Semantic'!
 !LexicalScope commentStamp!
 I represent a lexical scope where variable names are associated with ScopeVars
@@ -29,6 +29,14 @@ bindingFor: aStringOrNode
 			self temps at: aStringOrNode value ifAbsent: [ nil ]]]
 !
 
+blockIndex
+	^ blockIndex ifNil: [ 0 ]
+!
+
+blockIndex: anInteger 
+	blockIndex := anInteger
+!
+
 instruction
 	^ instruction
 !
@@ -380,7 +388,7 @@ isUnknownVar
 ! !
 
 NodeVisitor subclass: #SemanticAnalyzer
-	instanceVariableNames: 'currentScope theClass classReferences messageSends superSends'
+	instanceVariableNames: 'currentScope theClass classReferences messageSends superSends blockIndex'
 	package: 'Compiler-Semantic'!
 !SemanticAnalyzer commentStamp!
 I semantically analyze the abstract syntax tree and annotate it with informations such as non local returns and variable scopes.!
@@ -452,6 +460,15 @@ newScopeOfClass: aLexicalScopeClass
 		yourself
 ! !
 
+!SemanticAnalyzer methodsFor: 'private'!
+
+nextBlockIndex
+	blockIndex ifNil: [ blockIndex := 0 ].
+	
+	blockIndex := blockIndex + 1.
+	^ blockIndex
+! !
+
 !SemanticAnalyzer methodsFor: 'scope'!
 
 popScope
@@ -488,6 +505,7 @@ visitBlockNode: aNode
 	self pushScope: self newBlockScope.
 	aNode scope: currentScope.
 	currentScope node: aNode.
+	currentScope blockIndex: self nextBlockIndex.
 	
 	aNode parameters do: [ :each |
 		self validateVariableScope: each.

+ 1 - 1
st/Helios-Debugger.st

@@ -314,7 +314,7 @@ initializeContexts
 !
 
 initializeFromContext: aMethodContext
-	rootContext := aMethodContext aiContext.
+	rootContext := AIContext fromMethodContext: aMethodContext.
 	self initializeContexts
 ! !
 

+ 4 - 0
st/Kernel-Methods.st

@@ -564,6 +564,10 @@ home
 	<return self.homeContext>
 !
 
+index
+	<return self.index || 0>
+!
+
 locals
 	<return self.locals || {}>
 !