Forráskód Böngészése

Working compiler. No inlining yet

Nicolas Petton 12 éve
szülő
commit
219d6b567c

+ 34 - 1
js/Compiler-AST.deploy.js

@@ -340,6 +340,28 @@ return self;}
 }),
 smalltalk.CascadeNode);
 
+smalltalk.addMethod(
+"_alias",
+smalltalk.method({
+selector: "alias",
+fn: function () {
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(self, "_nodes", []), "_last", []), "_alias", []);
+return self;}
+}),
+smalltalk.CascadeNode);
+
+smalltalk.addMethod(
+"_beUsed",
+smalltalk.method({
+selector: "beUsed",
+fn: function () {
+var self=this;
+smalltalk.send(smalltalk.send(self, "_nodes", []), "_do_", [(function(each){return smalltalk.send(each, "_beUsed", []);})]);
+return self;}
+}),
+smalltalk.CascadeNode);
+
 smalltalk.addMethod(
 "_receiver",
 smalltalk.method({
@@ -495,6 +517,17 @@ return self;}
 }),
 smalltalk.MethodNode);
 
+smalltalk.addMethod(
+"_hasLocalReturn",
+smalltalk.method({
+selector: "hasLocalReturn",
+fn: function () {
+var self=this;
+return (($receiver = smalltalk.send(self, "_scope", [])) == nil || $receiver == undefined) ? (function(){return false;})() : (function(){return smalltalk.send(smalltalk.send(self, "_scope", []), "_hasLocalReturn", []);})();
+return self;}
+}),
+smalltalk.MethodNode);
+
 smalltalk.addMethod(
 "_hasNonLocalReturn",
 smalltalk.method({
@@ -1005,6 +1038,7 @@ smalltalk.method({
 selector: "beAssigned",
 fn: function () {
 var self=this;
+smalltalk.send(smalltalk.send(self, "_binding", []), "_validateAssignment", []);
 (self['@assigned']=true);
 return self;}
 }),
@@ -1027,7 +1061,6 @@ smalltalk.method({
 selector: "binding:",
 fn: function (aScopeVar) {
 var self=this;
-((($receiver = smalltalk.send(aScopeVar, "_isKindOf_", [(smalltalk.SemanticAnalyzer || SemanticAnalyzer)])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self, "_halt", []);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(self, "_halt", []);})]));
 (self['@binding']=aScopeVar);
 return self;}
 }),

+ 55 - 7
js/Compiler-AST.js

@@ -491,6 +491,38 @@ referencedClasses: []
 }),
 smalltalk.CascadeNode);
 
+smalltalk.addMethod(
+"_alias",
+smalltalk.method({
+selector: "alias",
+category: 'accessing',
+fn: function () {
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(self, "_nodes", []), "_last", []), "_alias", []);
+return self;},
+args: [],
+source: "alias\x0a\x09^self nodes last alias",
+messageSends: ["alias", "last", "nodes"],
+referencedClasses: []
+}),
+smalltalk.CascadeNode);
+
+smalltalk.addMethod(
+"_beUsed",
+smalltalk.method({
+selector: "beUsed",
+category: 'accessing',
+fn: function () {
+var self=this;
+smalltalk.send(smalltalk.send(self, "_nodes", []), "_do_", [(function(each){return smalltalk.send(each, "_beUsed", []);})]);
+return self;},
+args: [],
+source: "beUsed\x0a\x09self nodes do: [ :each | each beUsed ]",
+messageSends: ["do:", "nodes", "beUsed"],
+referencedClasses: []
+}),
+smalltalk.CascadeNode);
+
 smalltalk.addMethod(
 "_receiver",
 smalltalk.method({
@@ -711,11 +743,27 @@ referencedClasses: []
 }),
 smalltalk.MethodNode);
 
+smalltalk.addMethod(
+"_hasLocalReturn",
+smalltalk.method({
+selector: "hasLocalReturn",
+category: 'testing',
+fn: function () {
+var self=this;
+return (($receiver = smalltalk.send(self, "_scope", [])) == nil || $receiver == undefined) ? (function(){return false;})() : (function(){return smalltalk.send(smalltalk.send(self, "_scope", []), "_hasLocalReturn", []);})();
+return self;},
+args: [],
+source: "hasLocalReturn\x0a\x09^ self scope\x0a\x09\x09ifNil: [ false ]\x0a\x09\x09ifNotNil: [ self scope hasLocalReturn ]",
+messageSends: ["ifNil:ifNotNil:", "scope", "hasLocalReturn"],
+referencedClasses: []
+}),
+smalltalk.MethodNode);
+
 smalltalk.addMethod(
 "_hasNonLocalReturn",
 smalltalk.method({
 selector: "hasNonLocalReturn",
-category: 'accessing',
+category: 'testing',
 fn: function () {
 var self=this;
 return (($receiver = smalltalk.send(self, "_scope", [])) == nil || $receiver == undefined) ? (function(){return false;})() : (function(){return smalltalk.send(smalltalk.send(self, "_scope", []), "_hasNonLocalReturn", []);})();
@@ -1442,11 +1490,12 @@ selector: "beAssigned",
 category: 'accessing',
 fn: function () {
 var self=this;
+smalltalk.send(smalltalk.send(self, "_binding", []), "_validateAssignment", []);
 (self['@assigned']=true);
 return self;},
 args: [],
-source: "beAssigned\x0a\x09assigned := true",
-messageSends: [],
+source: "beAssigned\x0a\x09self binding validateAssignment.\x0a\x09assigned := true",
+messageSends: ["validateAssignment", "binding"],
 referencedClasses: []
 }),
 smalltalk.VariableNode);
@@ -1474,13 +1523,12 @@ selector: "binding:",
 category: 'accessing',
 fn: function (aScopeVar) {
 var self=this;
-((($receiver = smalltalk.send(aScopeVar, "_isKindOf_", [(smalltalk.SemanticAnalyzer || SemanticAnalyzer)])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self, "_halt", []);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(self, "_halt", []);})]));
 (self['@binding']=aScopeVar);
 return self;},
 args: ["aScopeVar"],
-source: "binding: aScopeVar\x0a\x09(aScopeVar isKindOf: SemanticAnalyzer) ifTrue: [ self halt ].\x0a\x09binding := aScopeVar",
-messageSends: ["ifTrue:", "isKindOf:", "halt"],
-referencedClasses: ["SemanticAnalyzer"]
+source: "binding: aScopeVar\x0a\x09binding := aScopeVar",
+messageSends: [],
+referencedClasses: []
 }),
 smalltalk.VariableNode);
 

+ 18 - 9
js/Compiler-Core.deploy.js

@@ -165,9 +165,9 @@ smalltalk.addMethod(
 "_recompile_",
 smalltalk.method({
 selector: "recompile:",
-fn: function (aClass) {
+fn: function (aClass){
 var self=this;
-smalltalk.send(smalltalk.send(aClass, "_methodDictionary", []), "_do_", [(function(each){return smalltalk.send(self, "_install_forClass_category_", [smalltalk.send(each, "_source", []), aClass, smalltalk.send(each, "_category", [])]);})]);
+smalltalk.send(smalltalk.send(aClass, "_methodDictionary", []), "_do_", [(function(each){smalltalk.send((typeof console == 'undefined' ? nil : console), "_log_", [smalltalk.send(smalltalk.send(smalltalk.send(aClass, "_name", []), "__comma", [" >> "]), "__comma", [smalltalk.send(each, "_selector", [])])]);return smalltalk.send(self, "_install_forClass_category_", [smalltalk.send(each, "_source", []), aClass, smalltalk.send(each, "_category", [])]);})]);
 smalltalk.send(self, "_setupClass_", [aClass]);
 ((($receiver = smalltalk.send(aClass, "_isMetaclass", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_recompile_", [smalltalk.send(aClass, "_class", [])]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_recompile_", [smalltalk.send(aClass, "_class", [])]);})]));
 return self;}
@@ -338,9 +338,9 @@ smalltalk.addMethod(
 "_visitClassReferenceNode_",
 smalltalk.method({
 selector: "visitClassReferenceNode:",
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+smalltalk.send(self, "_visitVariableNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -559,9 +559,18 @@ var ir=nil;
 var stream=nil;
 smalltalk.send(smalltalk.send(self, "_semanticAnalyzer", []), "_visit_", [aNode]);
 (ir=(function($rec){smalltalk.send($rec, "_visit_", [aNode]);return smalltalk.send($rec, "_builder", []);})(smalltalk.send(self, "_translator", [])));
-(stream=smalltalk.send((smalltalk.JSStream || JSStream), "_new", []));
-smalltalk.send(ir, "_emitOn_", [stream]);
-return smalltalk.send(stream, "_contents", []);
+return (function($rec){smalltalk.send($rec, "_visit_", [smalltalk.send(ir, "_method", [])]);return smalltalk.send($rec, "_contents", []);})(smalltalk.send(self, "_irTranslator", []));
+return self;}
+}),
+smalltalk.CodeGenerator);
+
+smalltalk.addMethod(
+"_irTranslator",
+smalltalk.method({
+selector: "irTranslator",
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRJSTranslator || IRJSTranslator), "_new", []);
 return self;}
 }),
 smalltalk.CodeGenerator);
@@ -581,9 +590,9 @@ smalltalk.addMethod(
 "_translator",
 smalltalk.method({
 selector: "translator",
-fn: function () {
+fn: function (){
 var self=this;
-return (function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRASTResolver || IRASTResolver), "_new", []));
+return (function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_theClass_", [smalltalk.send(self, "_currentClass", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRASTResolver || IRASTResolver), "_new", []));
 return self;}
 }),
 smalltalk.CodeGenerator);

+ 32 - 18
js/Compiler-Core.js

@@ -231,15 +231,15 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "recompile:",
 category: 'compiling',
-fn: function (aClass) {
+fn: function (aClass){
 var self=this;
-smalltalk.send(smalltalk.send(aClass, "_methodDictionary", []), "_do_", [(function(each){return smalltalk.send(self, "_install_forClass_category_", [smalltalk.send(each, "_source", []), aClass, smalltalk.send(each, "_category", [])]);})]);
+smalltalk.send(smalltalk.send(aClass, "_methodDictionary", []), "_do_", [(function(each){smalltalk.send((typeof console == 'undefined' ? nil : console), "_log_", [smalltalk.send(smalltalk.send(smalltalk.send(aClass, "_name", []), "__comma", [" >> "]), "__comma", [smalltalk.send(each, "_selector", [])])]);return smalltalk.send(self, "_install_forClass_category_", [smalltalk.send(each, "_source", []), aClass, smalltalk.send(each, "_category", [])]);})]);
 smalltalk.send(self, "_setupClass_", [aClass]);
 ((($receiver = smalltalk.send(aClass, "_isMetaclass", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_recompile_", [smalltalk.send(aClass, "_class", [])]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_recompile_", [smalltalk.send(aClass, "_class", [])]);})]));
 return self;},
 args: ["aClass"],
-source: "recompile: aClass\x0a\x09aClass methodDictionary do: [:each |\x0a\x09\x09self install: each source forClass: aClass category: each category].\x0a\x09self setupClass: aClass.\x0a\x09aClass isMetaclass ifFalse: [self recompile: aClass class]",
-messageSends: ["do:", "methodDictionary", "install:forClass:category:", "source", "category", "setupClass:", "ifFalse:", "isMetaclass", "recompile:", "class"],
+source: "recompile: aClass\x0a\x09aClass methodDictionary do: [:each |\x0a\x09\x09console log: aClass name, ' >> ', each selector.\x0a\x09\x09self install: each source forClass: aClass category: each category].\x0a\x09self setupClass: aClass.\x0a\x09aClass isMetaclass ifFalse: [self recompile: aClass class]",
+messageSends: ["do:", "methodDictionary", "log:", ",", "name", "selector", "install:forClass:category:", "source", "category", "setupClass:", "ifFalse:", "isMetaclass", "recompile:", "class"],
 referencedClasses: []
 }),
 smalltalk.Compiler);
@@ -479,13 +479,13 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitClassReferenceNode:",
 category: 'visiting',
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+smalltalk.send(self, "_visitVariableNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09self visitNode: aNode",
-messageSends: ["visitNode:"],
+source: "visitClassReferenceNode: aNode\x0a\x09self visitVariableNode: aNode",
+messageSends: ["visitVariableNode:"],
 referencedClasses: []
 }),
 smalltalk.NodeVisitor);
@@ -795,14 +795,28 @@ var ir=nil;
 var stream=nil;
 smalltalk.send(smalltalk.send(self, "_semanticAnalyzer", []), "_visit_", [aNode]);
 (ir=(function($rec){smalltalk.send($rec, "_visit_", [aNode]);return smalltalk.send($rec, "_builder", []);})(smalltalk.send(self, "_translator", [])));
-(stream=smalltalk.send((smalltalk.JSStream || JSStream), "_new", []));
-smalltalk.send(ir, "_emitOn_", [stream]);
-return smalltalk.send(stream, "_contents", []);
+return (function($rec){smalltalk.send($rec, "_visit_", [smalltalk.send(ir, "_method", [])]);return smalltalk.send($rec, "_contents", []);})(smalltalk.send(self, "_irTranslator", []));
 return self;},
 args: ["aNode"],
-source: "compileNode: aNode\x0a\x09| ir stream |\x0a\x09self semanticAnalyzer visit: aNode.\x0a\x09ir := self translator visit: aNode; builder.\x0a\x09stream := JSStream new.\x0a\x09ir emitOn: stream.\x0a\x09^ stream contents",
-messageSends: ["visit:", "semanticAnalyzer", "builder", "translator", "new", "emitOn:", "contents"],
-referencedClasses: ["JSStream"]
+source: "compileNode: aNode\x0a\x09| ir stream |\x0a\x09self semanticAnalyzer visit: aNode.\x0a\x09ir := self translator visit: aNode; builder.\x0a\x09^ self irTranslator\x0a\x09\x09visit: ir method;\x0a\x09\x09contents",
+messageSends: ["visit:", "semanticAnalyzer", "builder", "translator", "method", "contents", "irTranslator"],
+referencedClasses: []
+}),
+smalltalk.CodeGenerator);
+
+smalltalk.addMethod(
+"_irTranslator",
+smalltalk.method({
+selector: "irTranslator",
+category: 'compiling',
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRJSTranslator || IRJSTranslator), "_new", []);
+return self;},
+args: [],
+source: "irTranslator\x0a\x09^ IRJSTranslator new",
+messageSends: ["new"],
+referencedClasses: ["IRJSTranslator"]
 }),
 smalltalk.CodeGenerator);
 
@@ -827,13 +841,13 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "translator",
 category: 'compiling',
-fn: function () {
+fn: function (){
 var self=this;
-return (function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRASTResolver || IRASTResolver), "_new", []));
+return (function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_theClass_", [smalltalk.send(self, "_currentClass", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRASTResolver || IRASTResolver), "_new", []));
 return self;},
 args: [],
-source: "translator\x0a\x09^ IRASTResolver new\x0a\x09\x09source: self source;\x0a\x09\x09yourself",
-messageSends: ["source:", "source", "yourself", "new"],
+source: "translator\x0a\x09^ IRASTResolver new\x0a\x09\x09source: self source;\x0a\x09\x09theClass: self currentClass;\x0a\x09\x09yourself",
+messageSends: ["source:", "source", "theClass:", "currentClass", "yourself", "new"],
 referencedClasses: ["IRASTResolver"]
 }),
 smalltalk.CodeGenerator);

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 496 - 196
js/Compiler-IR.deploy.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 414 - 299
js/Compiler-IR.js


+ 180 - 29
js/Compiler-Semantic.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Semantic', {});
-smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'temps', 'args', 'outerScope'], 'Compiler-Semantic');
+smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'instruction', 'temps', 'args', 'outerScope'], 'Compiler-Semantic');
 smalltalk.addMethod(
 "_addArg_",
 smalltalk.method({
@@ -52,7 +52,29 @@ smalltalk.method({
 selector: "bindingFor:",
 fn: function (aStringOrNode) {
 var self=this;
-return smalltalk.send(smalltalk.send(self, "_args", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return smalltalk.send(smalltalk.send(self, "_temps", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return nil;})]);})]);
+return smalltalk.send(smalltalk.send(self, "_pseudoVars", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return smalltalk.send(smalltalk.send(self, "_args", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return smalltalk.send(smalltalk.send(self, "_temps", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return nil;})]);})]);})]);
+return self;}
+}),
+smalltalk.LexicalScope);
+
+smalltalk.addMethod(
+"_instruction",
+smalltalk.method({
+selector: "instruction",
+fn: function (){
+var self=this;
+return self['@instruction'];
+return self;}
+}),
+smalltalk.LexicalScope);
+
+smalltalk.addMethod(
+"_instruction_",
+smalltalk.method({
+selector: "instruction:",
+fn: function (anIRInstruction){
+var self=this;
+(self['@instruction']=anIRInstruction);
 return self;}
 }),
 smalltalk.LexicalScope);
@@ -137,6 +159,17 @@ return self;}
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_pseudoVars",
+smalltalk.method({
+selector: "pseudoVars",
+fn: function () {
+var self=this;
+return smalltalk.send(smalltalk.send(self, "_methodScope", []), "_pseudoVars", []);
+return self;}
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_scopeLevel",
 smalltalk.method({
@@ -161,12 +194,12 @@ smalltalk.LexicalScope);
 
 
 
-smalltalk.addClass('MethodLexicalScope', smalltalk.LexicalScope, ['iVars', 'unknownVariables', 'nonLocalReturn'], 'Compiler-Semantic');
+smalltalk.addClass('MethodLexicalScope', smalltalk.LexicalScope, ['iVars', 'unknownVariables', 'localReturn', 'nonLocalReturn'], 'Compiler-Semantic');
 smalltalk.addMethod(
-"_addIvar_",
+"_addIVar_",
 smalltalk.method({
-selector: "addIvar:",
-fn: function (aString) {
+selector: "addIVar:",
+fn: function (aString){
 var self=this;
 smalltalk.send(smalltalk.send(self, "_iVars", []), "_at_put_", [aString, smalltalk.send((smalltalk.InstanceVar || InstanceVar), "_on_", [aString])]);
 smalltalk.send(smalltalk.send(smalltalk.send(self, "_iVars", []), "_at_", [aString]), "_scope_", [self]);
@@ -196,6 +229,17 @@ return self;}
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_hasLocalReturn",
+smalltalk.method({
+selector: "hasLocalReturn",
+fn: function () {
+var self=this;
+return smalltalk.send(self, "_localReturn", []);
+return self;}
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_hasNonLocalReturn",
 smalltalk.method({
@@ -229,6 +273,28 @@ return self;}
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_localReturn",
+smalltalk.method({
+selector: "localReturn",
+fn: function () {
+var self=this;
+return (($receiver = self['@localReturn']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+return self;}
+}),
+smalltalk.MethodLexicalScope);
+
+smalltalk.addMethod(
+"_localReturn_",
+smalltalk.method({
+selector: "localReturn:",
+fn: function (aBoolean) {
+var self=this;
+(self['@localReturn']=aBoolean);
+return self;}
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_methodScope",
 smalltalk.method({
@@ -262,6 +328,18 @@ return self;}
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_pseudoVars",
+smalltalk.method({
+selector: "pseudoVars",
+fn: function () {
+var self=this;
+(($receiver = (typeof pseudoVars == 'undefined' ? nil : pseudoVars)) == nil || $receiver == undefined) ? (function(){(pseudoVars=smalltalk.send((smalltalk.Dictionary || Dictionary), "_new", []));return smalltalk.send(smalltalk.send(smalltalk.send((smalltalk.Smalltalk || Smalltalk), "_current", []), "_pseudoVariableNames", []), "_do_", [(function(each){return smalltalk.send((typeof pseudoVars == 'undefined' ? nil : pseudoVars), "_at_put_", [each, (function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(self, "_methodScope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.PseudoVar || PseudoVar), "_on_", [each]))]);})]);})() : $receiver;
+return (typeof pseudoVars == 'undefined' ? nil : pseudoVars);
+return self;}
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_unknownVariables",
 smalltalk.method({
@@ -298,6 +376,17 @@ return self;}
 }),
 smalltalk.ScopeVar);
 
+smalltalk.addMethod(
+"_isClassRefVar",
+smalltalk.method({
+selector: "isClassRefVar",
+fn: function (){
+var self=this;
+return false;
+return self;}
+}),
+smalltalk.ScopeVar);
+
 smalltalk.addMethod(
 "_isInstanceVar",
 smalltalk.method({
@@ -309,6 +398,17 @@ return self;}
 }),
 smalltalk.ScopeVar);
 
+smalltalk.addMethod(
+"_isPseudoVar",
+smalltalk.method({
+selector: "isPseudoVar",
+fn: function () {
+var self=this;
+return false;
+return self;}
+}),
+smalltalk.ScopeVar);
+
 smalltalk.addMethod(
 "_isTempVar",
 smalltalk.method({
@@ -375,6 +475,17 @@ return self;}
 }),
 smalltalk.ScopeVar);
 
+smalltalk.addMethod(
+"_validateAssignment",
+smalltalk.method({
+selector: "validateAssignment",
+fn: function () {
+var self=this;
+((($receiver = smalltalk.send(smalltalk.send(self, "_isArgVar", []), "_or_", [(function(){return smalltalk.send(self, "_isPseudoVar", []);})])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return (function($rec){smalltalk.send($rec, "_variableName_", [smalltalk.send(self, "_name", [])]);return smalltalk.send($rec, "_signal", []);})(smalltalk.send((smalltalk.InvalidAssignmentError || InvalidAssignmentError), "_new", []));})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return (function($rec){smalltalk.send($rec, "_variableName_", [smalltalk.send(self, "_name", [])]);return smalltalk.send($rec, "_signal", []);})(smalltalk.send((smalltalk.InvalidAssignmentError || InvalidAssignmentError), "_new", []));})]));
+return self;}
+}),
+smalltalk.ScopeVar);
+
 
 smalltalk.addMethod(
 "_on_",
@@ -432,9 +543,20 @@ smalltalk.addMethod(
 "_alias",
 smalltalk.method({
 selector: "alias",
-fn: function () {
+fn: function (){
 var self=this;
-return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("(Smalltalk.", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [" || "]), "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [")"]);
+return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("(smalltalk.", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [" || "]), "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [")"]);
+return self;}
+}),
+smalltalk.ClassRefVar);
+
+smalltalk.addMethod(
+"_isClassRefVar",
+smalltalk.method({
+selector: "isClassRefVar",
+fn: function (){
+var self=this;
+return true;
 return self;}
 }),
 smalltalk.ClassRefVar);
@@ -446,9 +568,9 @@ smalltalk.addMethod(
 "_alias",
 smalltalk.method({
 selector: "alias",
-fn: function () {
+fn: function (){
 var self=this;
-return smalltalk.send(smalltalk.send("self[\x22@", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", ["]"]);
+return smalltalk.send(smalltalk.send("self[\x22@", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", ["\x22]"]);
 return self;}
 }),
 smalltalk.InstanceVar);
@@ -466,6 +588,31 @@ smalltalk.InstanceVar);
 
 
 
+smalltalk.addClass('PseudoVar', smalltalk.ScopeVar, [], 'Compiler-Semantic');
+smalltalk.addMethod(
+"_alias",
+smalltalk.method({
+selector: "alias",
+fn: function () {
+var self=this;
+return smalltalk.send(self, "_name", []);
+return self;}
+}),
+smalltalk.PseudoVar);
+
+smalltalk.addMethod(
+"_isPseudoVar",
+smalltalk.method({
+selector: "isPseudoVar",
+fn: function () {
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.PseudoVar);
+
+
+
 smalltalk.addClass('TempVar', smalltalk.ScopeVar, [], 'Compiler-Semantic');
 smalltalk.addMethod(
 "_isTempVar",
@@ -517,17 +664,6 @@ return self;}
 }),
 smalltalk.SemanticAnalyzer);
 
-smalltalk.addMethod(
-"_errorInvalidAssignment_",
-smalltalk.method({
-selector: "errorInvalidAssignment:",
-fn: function (aString) {
-var self=this;
-(function($rec){smalltalk.send($rec, "_variableName_", [aString]);return smalltalk.send($rec, "_signal", []);})(smalltalk.send((smalltalk.InvalidAssignmentError || InvalidAssignmentError), "_new", []));
-return self;}
-}),
-smalltalk.SemanticAnalyzer);
-
 smalltalk.addMethod(
 "_errorShadowingVariable_",
 smalltalk.method({
@@ -668,8 +804,6 @@ selector: "visitAssignmentNode:",
 fn: function (aNode) {
 var self=this;
 smalltalk.send(self, "_visitAssignmentNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
-((($receiver = smalltalk.send(smalltalk.send(self, "_pseudoVariables", []), "_includes_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self, "_errorInvalidAssignment_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(self, "_errorInvalidAssignment_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])]);})]));
-((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_left", []), "_binding", []), "_isArgVar", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self, "_errorInvalidAssignment_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(self, "_errorInvalidAssignment_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])]);})]));
 smalltalk.send(smalltalk.send(aNode, "_left", []), "_beAssigned", []);
 smalltalk.send(smalltalk.send(aNode, "_right", []), "_beUsed", []);
 return self;}
@@ -695,11 +829,28 @@ smalltalk.addMethod(
 "_visitCascadeNode_",
 smalltalk.method({
 selector: "visitCascadeNode:",
-fn: function (aNode) {
-var self=this;
-smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(each, "_receiver_", [smalltalk.send(aNode, "_receiver", [])]);})]);
-smalltalk.send(self, "_visitCascadeNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
-return self;}
+fn: function (aNode){
+var self=this;
+var $1,$2,$3,$4,$5,$6,$7,$8,$9;
+$1=(function(each){
+$2=smalltalk.send(aNode,"_receiver",[]);
+return smalltalk.send(each,"_receiver_",[$2]);
+});
+$3=smalltalk.send(aNode,"_nodes",[]);
+smalltalk.send($3,"_do_",[$1]);
+smalltalk.send(self,"_visitCascadeNode_",[aNode],smalltalk.NodeVisitor);
+$4=(function(){
+$5=(function(each){
+return smalltalk.send(each,"_superSend_",[true]);
+});
+$6=smalltalk.send(aNode,"_nodes",[]);
+return smalltalk.send($6,"_do_",[$5]);
+});
+$7=smalltalk.send(aNode,"_nodes",[]);
+$8=smalltalk.send($7,"_first",[]);
+$9=smalltalk.send($8,"_superSend",[]);
+smalltalk.send($9,"_ifTrue_",[$4]);
+return self}
 }),
 smalltalk.SemanticAnalyzer);
 
@@ -738,7 +889,7 @@ smalltalk.method({
 selector: "visitReturnNode:",
 fn: function (aNode) {
 var self=this;
-((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
+((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);})() : (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);}), (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
 smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_first", []), "_beUsed", []);
 smalltalk.send(self, "_visitReturnNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;}

+ 257 - 45
js/Compiler-Semantic.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Semantic', {});
-smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'temps', 'args', 'outerScope'], 'Compiler-Semantic');
+smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'instruction', 'temps', 'args', 'outerScope'], '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(
 "_addArg_",
@@ -74,11 +74,43 @@ selector: "bindingFor:",
 category: 'accessing',
 fn: function (aStringOrNode) {
 var self=this;
-return smalltalk.send(smalltalk.send(self, "_args", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return smalltalk.send(smalltalk.send(self, "_temps", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return nil;})]);})]);
+return smalltalk.send(smalltalk.send(self, "_pseudoVars", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return smalltalk.send(smalltalk.send(self, "_args", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return smalltalk.send(smalltalk.send(self, "_temps", []), "_at_ifAbsent_", [smalltalk.send(aStringOrNode, "_value", []), (function(){return nil;})]);})]);})]);
 return self;},
 args: ["aStringOrNode"],
-source: "bindingFor: aStringOrNode\x0a\x09^ self args at: aStringOrNode value ifAbsent: [\x0a\x09\x09self temps at: aStringOrNode value ifAbsent: [ nil ]]",
-messageSends: ["at:ifAbsent:", "args", "value", "temps"],
+source: "bindingFor: aStringOrNode\x0a\x09^ self pseudoVars at: aStringOrNode value ifAbsent: [ \x0a\x09\x09self args at: aStringOrNode value ifAbsent: [\x0a\x09\x09\x09self temps at: aStringOrNode value ifAbsent: [ nil ]]]",
+messageSends: ["at:ifAbsent:", "pseudoVars", "value", "args", "temps"],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
+smalltalk.addMethod(
+"_instruction",
+smalltalk.method({
+selector: "instruction",
+category: 'accessing',
+fn: function (){
+var self=this;
+return self['@instruction'];
+return self;},
+args: [],
+source: "instruction\x0a\x09^ instruction",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
+smalltalk.addMethod(
+"_instruction_",
+smalltalk.method({
+selector: "instruction:",
+category: 'accessing',
+fn: function (anIRInstruction){
+var self=this;
+(self['@instruction']=anIRInstruction);
+return self;},
+args: ["anIRInstruction"],
+source: "instruction: anIRInstruction\x0a\x09instruction := anIRInstruction",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.LexicalScope);
@@ -198,6 +230,22 @@ referencedClasses: []
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_pseudoVars",
+smalltalk.method({
+selector: "pseudoVars",
+category: 'accessing',
+fn: function () {
+var self=this;
+return smalltalk.send(smalltalk.send(self, "_methodScope", []), "_pseudoVars", []);
+return self;},
+args: [],
+source: "pseudoVars\x0a\x09^ self methodScope pseudoVars",
+messageSends: ["pseudoVars", "methodScope"],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_scopeLevel",
 smalltalk.method({
@@ -232,20 +280,20 @@ smalltalk.LexicalScope);
 
 
 
-smalltalk.addClass('MethodLexicalScope', smalltalk.LexicalScope, ['iVars', 'unknownVariables', 'nonLocalReturn'], 'Compiler-Semantic');
+smalltalk.addClass('MethodLexicalScope', smalltalk.LexicalScope, ['iVars', 'unknownVariables', 'localReturn', 'nonLocalReturn'], 'Compiler-Semantic');
 smalltalk.MethodLexicalScope.comment="I represent a method scope."
 smalltalk.addMethod(
-"_addIvar_",
+"_addIVar_",
 smalltalk.method({
-selector: "addIvar:",
+selector: "addIVar:",
 category: 'adding',
-fn: function (aString) {
+fn: function (aString){
 var self=this;
 smalltalk.send(smalltalk.send(self, "_iVars", []), "_at_put_", [aString, smalltalk.send((smalltalk.InstanceVar || InstanceVar), "_on_", [aString])]);
 smalltalk.send(smalltalk.send(smalltalk.send(self, "_iVars", []), "_at_", [aString]), "_scope_", [self]);
 return self;},
 args: ["aString"],
-source: "addIvar: aString\x0a\x09self iVars at: aString put: (InstanceVar on: aString).\x0a\x09(self iVars at: aString) scope: self",
+source: "addIVar: aString\x0a\x09self iVars at: aString put: (InstanceVar on: aString).\x0a\x09(self iVars at: aString) scope: self",
 messageSends: ["at:put:", "iVars", "on:", "scope:", "at:"],
 referencedClasses: ["InstanceVar"]
 }),
@@ -283,6 +331,22 @@ referencedClasses: []
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_hasLocalReturn",
+smalltalk.method({
+selector: "hasLocalReturn",
+category: 'testing',
+fn: function () {
+var self=this;
+return smalltalk.send(self, "_localReturn", []);
+return self;},
+args: [],
+source: "hasLocalReturn\x0a\x09^ self localReturn",
+messageSends: ["localReturn"],
+referencedClasses: []
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_hasNonLocalReturn",
 smalltalk.method({
@@ -331,6 +395,38 @@ referencedClasses: []
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_localReturn",
+smalltalk.method({
+selector: "localReturn",
+category: 'accessing',
+fn: function () {
+var self=this;
+return (($receiver = self['@localReturn']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+return self;},
+args: [],
+source: "localReturn\x0a\x09^ localReturn ifNil: [ false ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+smalltalk.MethodLexicalScope);
+
+smalltalk.addMethod(
+"_localReturn_",
+smalltalk.method({
+selector: "localReturn:",
+category: 'accessing',
+fn: function (aBoolean) {
+var self=this;
+(self['@localReturn']=aBoolean);
+return self;},
+args: ["aBoolean"],
+source: "localReturn: aBoolean\x0a\x09localReturn := aBoolean",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_methodScope",
 smalltalk.method({
@@ -379,6 +475,23 @@ referencedClasses: []
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_pseudoVars",
+smalltalk.method({
+selector: "pseudoVars",
+category: 'accessing',
+fn: function () {
+var self=this;
+(($receiver = (typeof pseudoVars == 'undefined' ? nil : pseudoVars)) == nil || $receiver == undefined) ? (function(){(pseudoVars=smalltalk.send((smalltalk.Dictionary || Dictionary), "_new", []));return smalltalk.send(smalltalk.send(smalltalk.send((smalltalk.Smalltalk || Smalltalk), "_current", []), "_pseudoVariableNames", []), "_do_", [(function(each){return smalltalk.send((typeof pseudoVars == 'undefined' ? nil : pseudoVars), "_at_put_", [each, (function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(self, "_methodScope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.PseudoVar || PseudoVar), "_on_", [each]))]);})]);})() : $receiver;
+return (typeof pseudoVars == 'undefined' ? nil : pseudoVars);
+return self;},
+args: [],
+source: "pseudoVars\x0a\x09pseudoVars ifNil: [\x0a\x09\x09pseudoVars := Dictionary new.\x0a\x09\x09Smalltalk current pseudoVariableNames do: [ :each |\x0a\x09\x09\x09pseudoVars at: each put: ((PseudoVar on: each)\x0a\x09\x09\x09\x09scope: self methodScope;\x0a\x09\x09\x09\x09yourself) ]].\x0a\x09^ pseudoVars",
+messageSends: ["ifNil:", "new", "do:", "pseudoVariableNames", "current", "at:put:", "scope:", "methodScope", "yourself", "on:"],
+referencedClasses: ["Dictionary", "Smalltalk", "PseudoVar"]
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_unknownVariables",
 smalltalk.method({
@@ -431,6 +544,22 @@ referencedClasses: []
 }),
 smalltalk.ScopeVar);
 
+smalltalk.addMethod(
+"_isClassRefVar",
+smalltalk.method({
+selector: "isClassRefVar",
+category: 'testing',
+fn: function (){
+var self=this;
+return false;
+return self;},
+args: [],
+source: "isClassRefVar\x0a\x09^ false",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ScopeVar);
+
 smalltalk.addMethod(
 "_isInstanceVar",
 smalltalk.method({
@@ -447,6 +576,22 @@ referencedClasses: []
 }),
 smalltalk.ScopeVar);
 
+smalltalk.addMethod(
+"_isPseudoVar",
+smalltalk.method({
+selector: "isPseudoVar",
+category: 'testing',
+fn: function () {
+var self=this;
+return false;
+return self;},
+args: [],
+source: "isPseudoVar\x0a\x09^ false",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ScopeVar);
+
 smalltalk.addMethod(
 "_isTempVar",
 smalltalk.method({
@@ -543,6 +688,22 @@ referencedClasses: []
 }),
 smalltalk.ScopeVar);
 
+smalltalk.addMethod(
+"_validateAssignment",
+smalltalk.method({
+selector: "validateAssignment",
+category: 'testing',
+fn: function () {
+var self=this;
+((($receiver = smalltalk.send(smalltalk.send(self, "_isArgVar", []), "_or_", [(function(){return smalltalk.send(self, "_isPseudoVar", []);})])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return (function($rec){smalltalk.send($rec, "_variableName_", [smalltalk.send(self, "_name", [])]);return smalltalk.send($rec, "_signal", []);})(smalltalk.send((smalltalk.InvalidAssignmentError || InvalidAssignmentError), "_new", []));})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return (function($rec){smalltalk.send($rec, "_variableName_", [smalltalk.send(self, "_name", [])]);return smalltalk.send($rec, "_signal", []);})(smalltalk.send((smalltalk.InvalidAssignmentError || InvalidAssignmentError), "_new", []));})]));
+return self;},
+args: [],
+source: "validateAssignment\x0a\x09(self isArgVar or: [ self isPseudoVar ]) ifTrue: [\x0a\x09\x09InvalidAssignmentError new\x0a\x09\x09\x09variableName: self name;\x0a\x09\x09\x09signal]",
+messageSends: ["ifTrue:", "or:", "isArgVar", "isPseudoVar", "variableName:", "name", "signal", "new"],
+referencedClasses: ["InvalidAssignmentError"]
+}),
+smalltalk.ScopeVar);
+
 
 smalltalk.addMethod(
 "_on_",
@@ -624,17 +785,33 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "alias",
 category: 'accessing',
-fn: function () {
+fn: function (){
 var self=this;
-return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("(Smalltalk.", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [" || "]), "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [")"]);
+return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("(smalltalk.", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [" || "]), "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [")"]);
 return self;},
 args: [],
-source: "alias\x0a\x09^ '(Smalltalk.', self name, ' || ', self name, ')'",
+source: "alias\x0a\x09^ '(smalltalk.', self name, ' || ', self name, ')'",
 messageSends: [",", "name"],
 referencedClasses: []
 }),
 smalltalk.ClassRefVar);
 
+smalltalk.addMethod(
+"_isClassRefVar",
+smalltalk.method({
+selector: "isClassRefVar",
+category: 'testing',
+fn: function (){
+var self=this;
+return true;
+return self;},
+args: [],
+source: "isClassRefVar\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ClassRefVar);
+
 
 
 smalltalk.addClass('InstanceVar', smalltalk.ScopeVar, [], 'Compiler-Semantic');
@@ -644,12 +821,12 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "alias",
 category: 'testing',
-fn: function () {
+fn: function (){
 var self=this;
-return smalltalk.send(smalltalk.send("self[\x22@", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", ["]"]);
+return smalltalk.send(smalltalk.send("self[\x22@", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", ["\x22]"]);
 return self;},
 args: [],
-source: "alias\x0a\x09^ 'self[\x22@', self name, ']'",
+source: "alias\x0a\x09^ 'self[\x22@', self name, '\x22]'",
 messageSends: [",", "name"],
 referencedClasses: []
 }),
@@ -673,6 +850,42 @@ smalltalk.InstanceVar);
 
 
 
+smalltalk.addClass('PseudoVar', smalltalk.ScopeVar, [], 'Compiler-Semantic');
+smalltalk.PseudoVar.comment="I am an pseudo variable.\x0a\x0aThe five Smalltalk pseudo variables are: 'self', 'super', 'nil', 'true' and 'false'"
+smalltalk.addMethod(
+"_alias",
+smalltalk.method({
+selector: "alias",
+category: 'accessing',
+fn: function () {
+var self=this;
+return smalltalk.send(self, "_name", []);
+return self;},
+args: [],
+source: "alias\x0a\x09^ self name",
+messageSends: ["name"],
+referencedClasses: []
+}),
+smalltalk.PseudoVar);
+
+smalltalk.addMethod(
+"_isPseudoVar",
+smalltalk.method({
+selector: "isPseudoVar",
+category: 'testing',
+fn: function () {
+var self=this;
+return true;
+return self;},
+args: [],
+source: "isPseudoVar\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.PseudoVar);
+
+
+
 smalltalk.addClass('TempVar', smalltalk.ScopeVar, [], 'Compiler-Semantic');
 smalltalk.TempVar.comment="I am an temporary variable of a method or block."
 smalltalk.addMethod(
@@ -747,22 +960,6 @@ referencedClasses: ["Set"]
 }),
 smalltalk.SemanticAnalyzer);
 
-smalltalk.addMethod(
-"_errorInvalidAssignment_",
-smalltalk.method({
-selector: "errorInvalidAssignment:",
-category: 'error handling',
-fn: function (aString) {
-var self=this;
-(function($rec){smalltalk.send($rec, "_variableName_", [aString]);return smalltalk.send($rec, "_signal", []);})(smalltalk.send((smalltalk.InvalidAssignmentError || InvalidAssignmentError), "_new", []));
-return self;},
-args: ["aString"],
-source: "errorInvalidAssignment: aString\x0a\x09InvalidAssignmentError new\x0a\x09\x09variableName: aString;\x0a\x09\x09signal",
-messageSends: ["variableName:", "signal", "new"],
-referencedClasses: ["InvalidAssignmentError"]
-}),
-smalltalk.SemanticAnalyzer);
-
 smalltalk.addMethod(
 "_errorShadowingVariable_",
 smalltalk.method({
@@ -964,14 +1161,12 @@ category: 'visiting',
 fn: function (aNode) {
 var self=this;
 smalltalk.send(self, "_visitAssignmentNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
-((($receiver = smalltalk.send(smalltalk.send(self, "_pseudoVariables", []), "_includes_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self, "_errorInvalidAssignment_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(self, "_errorInvalidAssignment_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])]);})]));
-((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_left", []), "_binding", []), "_isArgVar", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self, "_errorInvalidAssignment_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(self, "_errorInvalidAssignment_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_value", [])]);})]));
 smalltalk.send(smalltalk.send(aNode, "_left", []), "_beAssigned", []);
 smalltalk.send(smalltalk.send(aNode, "_right", []), "_beUsed", []);
 return self;},
 args: ["aNode"],
-source: "visitAssignmentNode: aNode\x0a\x09super visitAssignmentNode: aNode.\x0a\x09(self pseudoVariables includes: aNode left value) ifTrue: [\x0a\x09\x09self errorInvalidAssignment: aNode left value ].\x0a\x09aNode left binding isArgVar ifTrue: [\x0a\x09\x09self errorInvalidAssignment: aNode left value ].\x0a\x09aNode left beAssigned.\x0a\x09aNode right beUsed.",
-messageSends: ["visitAssignmentNode:", "ifTrue:", "includes:", "pseudoVariables", "value", "left", "errorInvalidAssignment:", "isArgVar", "binding", "beAssigned", "beUsed", "right"],
+source: "visitAssignmentNode: aNode\x0a\x09super visitAssignmentNode: aNode.\x0a\x09aNode left beAssigned.\x0a\x09aNode right beUsed",
+messageSends: ["visitAssignmentNode:", "beAssigned", "left", "beUsed", "right"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1001,14 +1196,31 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitCascadeNode:",
 category: 'visiting',
-fn: function (aNode) {
-var self=this;
-smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(each, "_receiver_", [smalltalk.send(aNode, "_receiver", [])]);})]);
-smalltalk.send(self, "_visitCascadeNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
-return self;},
+fn: function (aNode){
+var self=this;
+var $1,$2,$3,$4,$5,$6,$7,$8,$9;
+$1=(function(each){
+$2=smalltalk.send(aNode,"_receiver",[]);
+return smalltalk.send(each,"_receiver_",[$2]);
+});
+$3=smalltalk.send(aNode,"_nodes",[]);
+smalltalk.send($3,"_do_",[$1]);
+smalltalk.send(self,"_visitCascadeNode_",[aNode],smalltalk.NodeVisitor);
+$4=(function(){
+$5=(function(each){
+return smalltalk.send(each,"_superSend_",[true]);
+});
+$6=smalltalk.send(aNode,"_nodes",[]);
+return smalltalk.send($6,"_do_",[$5]);
+});
+$7=smalltalk.send(aNode,"_nodes",[]);
+$8=smalltalk.send($7,"_first",[]);
+$9=smalltalk.send($8,"_superSend",[]);
+smalltalk.send($9,"_ifTrue_",[$4]);
+return self},
 args: ["aNode"],
-source: "visitCascadeNode: aNode\x0a\x09\x22Populate the receiver into all children\x22\x0a\x09aNode nodes do: [ :each | each receiver: aNode receiver ].\x0a\x09super visitCascadeNode: aNode",
-messageSends: ["do:", "nodes", "receiver:", "receiver", "visitCascadeNode:"],
+source: "visitCascadeNode: aNode\x0a\x09\x22Populate the receiver into all children\x22\x0a\x09aNode nodes do: [ :each | \x0a\x09\x09each receiver: aNode receiver ].\x0a\x09super visitCascadeNode: aNode.\x0a\x09aNode nodes first superSend ifTrue: [\x0a\x09\x09aNode nodes do: [ :each | each superSend: true ]]",
+messageSends: ["do:", "receiver:", "receiver", "nodes", "visitCascadeNode:", "ifTrue:", "superSend:", "superSend", "first"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1059,13 +1271,13 @@ selector: "visitReturnNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
+((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);})() : (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);}), (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
 smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_first", []), "_beUsed", []);
 smalltalk.send(self, "_visitReturnNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;},
 args: ["aNode"],
-source: "visitReturnNode: aNode\x0a\x09currentScope isMethodScope ifFalse: [\x0a\x09\x09currentScope methodScope nonLocalReturn: true.\x0a\x09\x09aNode nonLocalReturn: true ].\x0a\x09aNode nodes first beUsed.\x0a\x09super visitReturnNode: aNode",
-messageSends: ["ifFalse:", "isMethodScope", "nonLocalReturn:", "methodScope", "beUsed", "first", "nodes", "visitReturnNode:"],
+source: "visitReturnNode: aNode\x0a\x09currentScope isMethodScope \x0a\x09\x09ifTrue: [ currentScope localReturn: true ]\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09currentScope methodScope nonLocalReturn: true.\x0a\x09\x09\x09aNode nonLocalReturn: true ].\x0a\x09aNode nodes first beUsed.\x0a\x09super visitReturnNode: aNode",
+messageSends: ["ifTrue:ifFalse:", "isMethodScope", "localReturn:", "nonLocalReturn:", "methodScope", "beUsed", "first", "nodes", "visitReturnNode:"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);

+ 90 - 0
js/Compiler-Tests.deploy.js

@@ -1,4 +1,94 @@
 smalltalk.addPackage('Compiler-Tests', {});
+smalltalk.addClass('IRASTTranslatorTest', smalltalk.TestCase, [], 'Compiler-Tests');
+smalltalk.addMethod(
+"_testIRMethod",
+smalltalk.method({
+selector: "testIRMethod",
+fn: function (){
+var self=this;
+
+return self;}
+}),
+smalltalk.IRASTTranslatorTest);
+
+
+
+smalltalk.addClass('ScopeVarTest', smalltalk.TestCase, [], 'Compiler-Tests');
+smalltalk.addMethod(
+"_testClassRefVar",
+smalltalk.method({
+selector: "testClassRefVar",
+fn: function (){
+var self=this;
+var node=nil;
+(node=(function($rec){smalltalk.send($rec, "_value_", ["Object"]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.ClassReferenceNode || ClassReferenceNode), "_new", [])));
+smalltalk.send(smalltalk.send((smalltalk.SemanticAnalyzer || SemanticAnalyzer), "_new", []), "_visit_", [node]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(node, "_binding", []), "_isClassRefVar", [])]);
+return self;}
+}),
+smalltalk.ScopeVarTest);
+
+smalltalk.addMethod(
+"_testInstanceVar",
+smalltalk.method({
+selector: "testInstanceVar",
+fn: function (){
+var self=this;
+var node=nil;
+var scope=nil;
+(node=(function($rec){smalltalk.send($rec, "_value_", ["bzzz"]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.VariableNode || VariableNode), "_new", [])));
+(scope=smalltalk.send((smalltalk.MethodLexicalScope || MethodLexicalScope), "_new", []));
+smalltalk.send(scope, "_addIVar_", ["bzzz"]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(scope, "_bindingFor_", [node]), "_isInstanceVar", [])]);
+return self;}
+}),
+smalltalk.ScopeVarTest);
+
+smalltalk.addMethod(
+"_testPseudoVar",
+smalltalk.method({
+selector: "testPseudoVar",
+fn: function (){
+var self=this;
+var node=nil;
+var pseudoVars=nil;
+(pseudoVars=["self", "super", "true", "false", "nil"]);
+smalltalk.send(pseudoVars, "_do_", [(function(each){(node=(function($rec){smalltalk.send($rec, "_value_", [each]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.VariableNode || VariableNode), "_new", [])));return smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(smalltalk.send((smalltalk.MethodLexicalScope || MethodLexicalScope), "_new", []), "_bindingFor_", [node]), "_isPseudoVar", [])]);})]);
+return self;}
+}),
+smalltalk.ScopeVarTest);
+
+smalltalk.addMethod(
+"_testTempVar",
+smalltalk.method({
+selector: "testTempVar",
+fn: function (){
+var self=this;
+var node=nil;
+var scope=nil;
+(node=(function($rec){smalltalk.send($rec, "_value_", ["bzzz"]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.VariableNode || VariableNode), "_new", [])));
+(scope=smalltalk.send((smalltalk.MethodLexicalScope || MethodLexicalScope), "_new", []));
+smalltalk.send(scope, "_addTemp_", ["bzzz"]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(scope, "_bindingFor_", [node]), "_isTempVar", [])]);
+return self;}
+}),
+smalltalk.ScopeVarTest);
+
+smalltalk.addMethod(
+"_testUnknownVar",
+smalltalk.method({
+selector: "testUnknownVar",
+fn: function (){
+var self=this;
+var node=nil;
+(node=(function($rec){smalltalk.send($rec, "_value_", ["bzzz"]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.VariableNode || VariableNode), "_new", [])));
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(smalltalk.send((smalltalk.MethodLexicalScope || MethodLexicalScope), "_new", []), "_bindingFor_", [node]), "_isNil", [])]);
+return self;}
+}),
+smalltalk.ScopeVarTest);
+
+
+
 smalltalk.addClass('SemanticAnalyzerTest', smalltalk.TestCase, ['analyzer'], 'Compiler-Tests');
 smalltalk.addMethod(
 "_setUp",

+ 120 - 0
js/Compiler-Tests.js

@@ -1,4 +1,124 @@
 smalltalk.addPackage('Compiler-Tests', {});
+smalltalk.addClass('IRASTTranslatorTest', smalltalk.TestCase, [], 'Compiler-Tests');
+smalltalk.addMethod(
+"_testIRMethod",
+smalltalk.method({
+selector: "testIRMethod",
+category: 'tests',
+fn: function (){
+var self=this;
+
+return self;},
+args: [],
+source: "testIRMethod",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRASTTranslatorTest);
+
+
+
+smalltalk.addClass('ScopeVarTest', smalltalk.TestCase, [], 'Compiler-Tests');
+smalltalk.addMethod(
+"_testClassRefVar",
+smalltalk.method({
+selector: "testClassRefVar",
+category: 'tests',
+fn: function (){
+var self=this;
+var node=nil;
+(node=(function($rec){smalltalk.send($rec, "_value_", ["Object"]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.ClassReferenceNode || ClassReferenceNode), "_new", [])));
+smalltalk.send(smalltalk.send((smalltalk.SemanticAnalyzer || SemanticAnalyzer), "_new", []), "_visit_", [node]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(node, "_binding", []), "_isClassRefVar", [])]);
+return self;},
+args: [],
+source: "testClassRefVar\x0a\x09| node |\x0a\x09node := ClassReferenceNode new\x0a\x09\x09value: 'Object';\x0a\x09\x09yourself.\x0a\x09SemanticAnalyzer new visit: node.\x0a\x09self assert: node binding isClassRefVar",
+messageSends: ["value:", "yourself", "new", "visit:", "assert:", "isClassRefVar", "binding"],
+referencedClasses: ["ClassReferenceNode", "SemanticAnalyzer"]
+}),
+smalltalk.ScopeVarTest);
+
+smalltalk.addMethod(
+"_testInstanceVar",
+smalltalk.method({
+selector: "testInstanceVar",
+category: 'tests',
+fn: function (){
+var self=this;
+var node=nil;
+var scope=nil;
+(node=(function($rec){smalltalk.send($rec, "_value_", ["bzzz"]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.VariableNode || VariableNode), "_new", [])));
+(scope=smalltalk.send((smalltalk.MethodLexicalScope || MethodLexicalScope), "_new", []));
+smalltalk.send(scope, "_addIVar_", ["bzzz"]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(scope, "_bindingFor_", [node]), "_isInstanceVar", [])]);
+return self;},
+args: [],
+source: "testInstanceVar\x0a\x09| node scope |\x0a\x09node := VariableNode new\x0a\x09\x09value: 'bzzz';\x0a\x09\x09yourself.\x0a\x09scope := MethodLexicalScope new.\x0a\x09scope addIVar: 'bzzz'.\x0a\x09self assert: (scope bindingFor: node) isInstanceVar",
+messageSends: ["value:", "yourself", "new", "addIVar:", "assert:", "isInstanceVar", "bindingFor:"],
+referencedClasses: ["VariableNode", "MethodLexicalScope"]
+}),
+smalltalk.ScopeVarTest);
+
+smalltalk.addMethod(
+"_testPseudoVar",
+smalltalk.method({
+selector: "testPseudoVar",
+category: 'tests',
+fn: function (){
+var self=this;
+var node=nil;
+var pseudoVars=nil;
+(pseudoVars=["self", "super", "true", "false", "nil"]);
+smalltalk.send(pseudoVars, "_do_", [(function(each){(node=(function($rec){smalltalk.send($rec, "_value_", [each]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.VariableNode || VariableNode), "_new", [])));return smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(smalltalk.send((smalltalk.MethodLexicalScope || MethodLexicalScope), "_new", []), "_bindingFor_", [node]), "_isPseudoVar", [])]);})]);
+return self;},
+args: [],
+source: "testPseudoVar\x0a\x09| node pseudoVars |\x0a\x09pseudoVars := #('self' 'super' 'true' 'false' 'nil').\x0a\x09pseudoVars do: [:each |\x0a\x09\x09node := VariableNode new\x0a\x09\x09value: each;\x0a\x09\x09yourself.\x0a\x09\x09self assert: (MethodLexicalScope new bindingFor: node) isPseudoVar ]",
+messageSends: ["do:", "value:", "yourself", "new", "assert:", "isPseudoVar", "bindingFor:"],
+referencedClasses: ["VariableNode", "MethodLexicalScope"]
+}),
+smalltalk.ScopeVarTest);
+
+smalltalk.addMethod(
+"_testTempVar",
+smalltalk.method({
+selector: "testTempVar",
+category: 'tests',
+fn: function (){
+var self=this;
+var node=nil;
+var scope=nil;
+(node=(function($rec){smalltalk.send($rec, "_value_", ["bzzz"]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.VariableNode || VariableNode), "_new", [])));
+(scope=smalltalk.send((smalltalk.MethodLexicalScope || MethodLexicalScope), "_new", []));
+smalltalk.send(scope, "_addTemp_", ["bzzz"]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(scope, "_bindingFor_", [node]), "_isTempVar", [])]);
+return self;},
+args: [],
+source: "testTempVar\x0a\x09| node scope |\x0a\x09node := VariableNode new\x0a\x09\x09value: 'bzzz';\x0a\x09\x09yourself.\x0a\x09scope := MethodLexicalScope new.\x0a\x09scope addTemp: 'bzzz'.\x0a\x09self assert: (scope bindingFor: node) isTempVar",
+messageSends: ["value:", "yourself", "new", "addTemp:", "assert:", "isTempVar", "bindingFor:"],
+referencedClasses: ["VariableNode", "MethodLexicalScope"]
+}),
+smalltalk.ScopeVarTest);
+
+smalltalk.addMethod(
+"_testUnknownVar",
+smalltalk.method({
+selector: "testUnknownVar",
+category: 'tests',
+fn: function (){
+var self=this;
+var node=nil;
+(node=(function($rec){smalltalk.send($rec, "_value_", ["bzzz"]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.VariableNode || VariableNode), "_new", [])));
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(smalltalk.send((smalltalk.MethodLexicalScope || MethodLexicalScope), "_new", []), "_bindingFor_", [node]), "_isNil", [])]);
+return self;},
+args: [],
+source: "testUnknownVar\x0a\x09| node |\x0a\x09node := VariableNode new\x0a\x09\x09value: 'bzzz';\x0a\x09\x09yourself.\x0a\x09self assert: (MethodLexicalScope new bindingFor: node) isNil",
+messageSends: ["value:", "yourself", "new", "assert:", "isNil", "bindingFor:"],
+referencedClasses: ["VariableNode", "MethodLexicalScope"]
+}),
+smalltalk.ScopeVarTest);
+
+
+
 smalltalk.addClass('SemanticAnalyzerTest', smalltalk.TestCase, ['analyzer'], 'Compiler-Tests');
 smalltalk.addMethod(
 "_setUp",

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 118
js/Compiler-Visitors.deploy.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 159
js/Compiler-Visitors.js


+ 27 - 0
js/Kernel-Classes.deploy.js

@@ -310,6 +310,17 @@ smalltalk.Behavior);
 
 
 smalltalk.addClass('Class', smalltalk.Behavior, [], 'Kernel-Classes');
+smalltalk.addMethod(
+"_asJavascript",
+smalltalk.method({
+selector: "asJavascript",
+fn: function (){
+var self=this;
+return smalltalk.send("smalltalk.", "__comma", [smalltalk.send(self, "_name", [])]);
+return self;}
+}),
+smalltalk.Class);
+
 smalltalk.addMethod(
 "_category",
 smalltalk.method({
@@ -428,6 +439,22 @@ smalltalk.Class);
 
 
 smalltalk.addClass('Metaclass', smalltalk.Behavior, [], 'Kernel-Classes');
+smalltalk.addMethod(
+"_asJavascript",
+smalltalk.method({
+selector: "asJavascript",
+fn: function (){
+var self=this;
+var $1,$2,$3,$4;
+$1=smalltalk.send(self,"_instanceClass",[]);
+$2=smalltalk.send($1,"_name",[]);
+$3=smalltalk.send("smalltalk.","__comma",[$2]);
+$4=smalltalk.send($3,"__comma",[".klass"]);
+return $4;
+}
+}),
+smalltalk.Metaclass);
+
 smalltalk.addMethod(
 "_instanceClass",
 smalltalk.method({

+ 37 - 0
js/Kernel-Classes.js

@@ -442,6 +442,22 @@ smalltalk.Behavior);
 
 smalltalk.addClass('Class', smalltalk.Behavior, [], 'Kernel-Classes');
 smalltalk.Class.comment="Class is __the__ class object. \x0a\x0aInstances are the classes of the system.\x0aClass creation is done throught a `ClassBuilder`"
+smalltalk.addMethod(
+"_asJavascript",
+smalltalk.method({
+selector: "asJavascript",
+category: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.send("smalltalk.", "__comma", [smalltalk.send(self, "_name", [])]);
+return self;},
+args: [],
+source: "asJavascript\x0a\x09^ 'smalltalk.', self name",
+messageSends: [",", "name"],
+referencedClasses: []
+}),
+smalltalk.Class);
+
 smalltalk.addMethod(
 "_category",
 smalltalk.method({
@@ -611,6 +627,27 @@ smalltalk.Class);
 
 smalltalk.addClass('Metaclass', smalltalk.Behavior, [], 'Kernel-Classes');
 smalltalk.Metaclass.comment="Metaclass is the root of the class hierarchy.\x0a\x0aMetaclass instances are metaclasses, one for each real class. \x0aMetaclass instances have a single instance, which they hold onto, which is the class that they are the metaclass of."
+smalltalk.addMethod(
+"_asJavascript",
+smalltalk.method({
+selector: "asJavascript",
+category: 'converting',
+fn: function (){
+var self=this;
+var $1,$2,$3,$4;
+$1=smalltalk.send(self,"_instanceClass",[]);
+$2=smalltalk.send($1,"_name",[]);
+$3=smalltalk.send("smalltalk.","__comma",[$2]);
+$4=smalltalk.send($3,"__comma",[".klass"]);
+return $4;
+},
+args: [],
+source: "asJavascript\x0a\x09^ 'smalltalk.', self instanceClass name, '.klass'",
+messageSends: [",", "name", "instanceClass"],
+referencedClasses: []
+}),
+smalltalk.Metaclass);
+
 smalltalk.addMethod(
 "_instanceClass",
 smalltalk.method({

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

@@ -2603,6 +2603,17 @@ return self;}
 }),
 smalltalk.Smalltalk);
 
+smalltalk.addMethod(
+"_pseudoVariableNames",
+smalltalk.method({
+selector: "pseudoVariableNames",
+fn: function () {
+var self=this;
+return ["self", "super", "nil", "true", "false"];
+return self;}
+}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 "_readJSObject_",
 smalltalk.method({

+ 16 - 0
js/Kernel-Objects.js

@@ -3717,6 +3717,22 @@ referencedClasses: ["String", "ParseError"]
 }),
 smalltalk.Smalltalk);
 
+smalltalk.addMethod(
+"_pseudoVariableNames",
+smalltalk.method({
+selector: "pseudoVariableNames",
+category: 'packages',
+fn: function () {
+var self=this;
+return ["self", "super", "nil", "true", "false"];
+return self;},
+args: [],
+source: "pseudoVariableNames\x0a\x09^ #('self' 'super' 'nil' 'true' 'false')",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 "_readJSObject_",
 smalltalk.method({

+ 0 - 1
js/amber.js

@@ -88,7 +88,6 @@ amber = (function() {
 				'Compiler-Exceptions',
 				'Compiler-Core',
 				'Compiler-AST',
-				'Compiler-Visitors',
 				'Compiler-Semantic',
 				'Compiler-IR',
 				'Compiler-Tests',

+ 21 - 7
st/Compiler-AST.st

@@ -154,6 +154,14 @@ Node subclass: #CascadeNode
 
 !CascadeNode methodsFor: 'accessing'!
 
+alias
+	^self nodes last alias
+!
+
+beUsed
+	self nodes do: [ :each | each beUsed ]
+!
+
 receiver
 	^receiver
 !
@@ -230,12 +238,6 @@ classReferences: aCollection
 	classReferences := aCollection
 !
 
-hasNonLocalReturn
-	^ self scope
-		ifNil: [ false ]
-		ifNotNil: [ self scope hasNonLocalReturn ]
-!
-
 messageSends
 	^ messageSends
 !
@@ -272,6 +274,18 @@ source: aString
 
 canAliasChildren
 	^ false
+!
+
+hasLocalReturn
+	^ self scope
+		ifNil: [ false ]
+		ifNotNil: [ self scope hasLocalReturn ]
+!
+
+hasNonLocalReturn
+	^ self scope
+		ifNil: [ false ]
+		ifNotNil: [ self scope hasNonLocalReturn ]
 ! !
 
 !MethodNode methodsFor: 'visiting'!
@@ -490,6 +504,7 @@ assigned: aBoolean
 !
 
 beAssigned
+	self binding validateAssignment.
 	assigned := true
 !
 
@@ -498,7 +513,6 @@ binding
 !
 
 binding: aScopeVar
-	(aScopeVar isKindOf: SemanticAnalyzer) ifTrue: [ self halt ].
 	binding := aScopeVar
 ! !
 

+ 10 - 4
st/Compiler-Core.st

@@ -97,6 +97,7 @@ parseExpression: aString
 
 recompile: aClass
 	aClass methodDictionary do: [:each |
+		console log: aClass name, ' >> ', each selector.
 		self install: each source forClass: aClass category: each category].
 	self setupClass: aClass.
 	aClass isMetaclass ifFalse: [self recompile: aClass class]
@@ -158,7 +159,7 @@ visitCascadeNode: aNode
 !
 
 visitClassReferenceNode: aNode
-	self visitNode: aNode
+	self visitVariableNode: aNode
 !
 
 visitDynamicArrayNode: aNode
@@ -258,9 +259,13 @@ compileNode: aNode
 	| ir stream |
 	self semanticAnalyzer visit: aNode.
 	ir := self translator visit: aNode; builder.
-	stream := JSStream new.
-	ir emitOn: stream.
-	^ stream contents
+	^ self irTranslator
+		visit: ir method;
+		contents
+!
+
+irTranslator
+	^ IRJSTranslator new
 !
 
 semanticAnalyzer
@@ -270,6 +275,7 @@ semanticAnalyzer
 translator
 	^ IRASTResolver new
 		source: self source;
+		theClass: self currentClass;
 		yourself
 ! !
 

+ 315 - 197
st/Compiler-IR.st

@@ -1,13 +1,10 @@
 Smalltalk current createPackage: 'Compiler-IR' properties: #{}!
 NodeVisitor subclass: #IRASTTranslator
-	instanceVariableNames: 'builder source'
+	instanceVariableNames: 'builder source theClass'
 	package: 'Compiler-IR'!
 !IRASTTranslator commentStamp!
 I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.
-I rely on a builder object, instance of IRBuilder.
-
-I am myself unable to produce a valid IR as nodes are not resolved. 
-See concrete subclasses.!
+I rely on a builder object, instance of IRBuilder.!
 
 !IRASTTranslator methodsFor: 'accessing'!
 
@@ -25,6 +22,14 @@ source
 
 source: aString
 	source := aString
+!
+
+theClass
+	^ theClass
+!
+
+theClass: aClass
+	theClass := aClass
 ! !
 
 !IRASTTranslator methodsFor: 'visiting'!
@@ -37,16 +42,25 @@ visitAssignmentNode: aNode
 
 visitBlockNode: aNode
 	self builder closure 
-		with: [ super visitBlockNode: aNode ];
+		with: [ 
+			aNode scope temps do: [ :each |
+				self builder tempDeclaration name: each name ].
+			super visitBlockNode: aNode ];
 		arguments: aNode parameters
 !
 
+visitBlockSequenceNode: aNode
+	self builder blockSequence with: [
+		aNode nodes do: [ :each | self visit: each ]]
+!
+
 visitJSStatementNode: aNode
 	self builder verbatim: aNode source
 !
 
 visitMethodNode: aNode
 	self builder method 
+		scope: aNode scope;
 		source: self source;
 		arguments: aNode arguments;
 		selector: aNode selector;
@@ -58,7 +72,11 @@ visitMethodNode: aNode
 	aNode hasNonLocalReturn 
 		ifTrue: [ self builder nonLocalReturnHandling with: [
 			super visitMethodNode: aNode ]]
-		ifFalse: [ super visitMethodNode: aNode ]
+		ifFalse: [ super visitMethodNode: aNode ].
+
+	aNode hasLocalReturn ifFalse: [
+		self builder return with: [
+			self builder variable: (aNode scope pseudoVars at: 'self') ]]
 !
 
 visitReturnNode: aNode
@@ -68,12 +86,13 @@ visitReturnNode: aNode
 !
 
 visitSendNode: aNode
-	self builder send
-		selector: aNode selector;
-		superSend: aNode superSend;
-		with: [
-			self visit: aNode receiver.
-			(aNode arguments do: [ :each | self visit: each ]) ]
+	| send |
+	send := self builder send.
+	send selector: aNode selector.
+	aNode superSend ifTrue: [ send classSend: self theClass superclass ].
+	send with: [
+		self visit: aNode receiver.
+		(aNode arguments do: [ :each | self visit: each ]) ]
 !
 
 visitSequenceNode: aNode
@@ -113,16 +132,16 @@ resolve: aNode
 	aNode isBlockSequenceNode ifFalse: [
 		aNode nodes do: [ :each | self resolve: each ]].
 	aNode shouldBeAliased ifTrue: [
-		| alias |
-		alias := self nextAlias.
-		self builder method internalVariables add: alias.
-		self builder assignment
-			with: [ self builder variable: (AliasVar new 
-				name: alias;
-				node: aNode;
-				yourself) ];
-			with: [ self visit: aNode resolving: false ].
-			aNode alias: alias ]
+			| alias |
+			alias := self nextAlias.
+			self builder method internalVariables add: alias.
+			self builder alias
+				with: [ self builder variable: (AliasVar new 
+					name: alias;
+					node: aNode;
+					yourself) ];
+				with: [ self visit: aNode resolving: false ].
+				aNode alias: alias ]
 !
 
 visit: aNode
@@ -141,6 +160,15 @@ visitAliased: aNode
 		name: aNode alias;
 		node: aNode;
 		yourself)
+!
+
+visitCascadeNode: aNode
+	"Special care must be taken for cascade nodes.
+	Only the last node should be aliased if any"
+
+	aNode nodes allButLast do: [ :each |
+		self visit: each resolving: false ].
+	self visit: aNode nodes last
 ! !
 
 Object subclass: #IRBuilder
@@ -175,6 +203,10 @@ add: aClass
 	^ self root append: (aClass on: self)
 !
 
+alias
+	^ self add: IRAlias
+!
+
 append: anObject
 	^root append: anObject
 !
@@ -183,6 +215,10 @@ assignment
 	^ self add: IRAssignment
 !
 
+blockSequence
+	^ self add: IRBlockSequence
+!
+
 closure
 	^ self add: IRClosure
 !
@@ -258,10 +294,6 @@ initialize
 	root := method := IRMethod on: self
 ! !
 
-Object subclass: #IRInliner
-	instanceVariableNames: ''
-	package: 'Compiler-IR'!
-
 Object subclass: #IRInstruction
 	instanceVariableNames: 'builder instructions'
 	package: 'Compiler-IR'!
@@ -314,14 +346,14 @@ with: anObject
 	anObject appendToInstruction: self
 ! !
 
-!IRInstruction methodsFor: 'emiting'!
+!IRInstruction methodsFor: 'testing'!
 
-emitOn: aStream
-	"Just emit all sub instructions to aStream.
-	Subclasses should not forget to call `super emitOn:`"
+isClosure
+	^ false
+!
 
-	self instructions do: [ :each |
-		each emitOn: aStream ]
+isInlined
+	^ false
 ! !
 
 !IRInstruction methodsFor: 'visiting'!
@@ -339,25 +371,82 @@ on: aBuilder
 ! !
 
 IRInstruction subclass: #IRAssignment
-	instanceVariableNames: 'left right'
+	instanceVariableNames: ''
 	package: 'Compiler-IR'!
 
-!IRAssignment methodsFor: 'emiting'!
+!IRAssignment methodsFor: 'visiting'!
 
-emitOn: aStream
-	aStream 
-		nextPutAssignment: self instructions first 
-		to: self instructions last
+accept: aVisitor
+	aVisitor visitIRAssignment: self
 ! !
 
-!IRAssignment methodsFor: 'visiting'!
+IRAssignment subclass: #IRAlias
+	instanceVariableNames: ''
+	package: 'Compiler-IR'!
+
+!IRAlias methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRAssignment: self
+	aVisitor visitIRAlias: self
+! !
+
+IRInstruction subclass: #IRNonLocalReturn
+	instanceVariableNames: ''
+	package: 'Compiler-IR'!
+!IRNonLocalReturn commentStamp!
+I am a non local return instruction.
+Non local returns are handled using a try/catch JS statement.
+
+See IRNonLocalReturnHandling class!
+
+!IRNonLocalReturn methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRNonLocalReturn: self
+! !
+
+IRInstruction subclass: #IRNonLocalReturnHandling
+	instanceVariableNames: ''
+	package: 'Compiler-IR'!
+!IRNonLocalReturnHandling commentStamp!
+I represent a non local return handling instruction.
+Non local returns are handled with a try/catch statement!
+
+!IRNonLocalReturnHandling methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRNonLocalReturnHandling: self
+! !
+
+IRInstruction subclass: #IRReturn
+	instanceVariableNames: ''
+	package: 'Compiler-IR'!
+!IRReturn commentStamp!
+I am a local return instruction.!
+
+!IRReturn methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRReturn: self
 ! !
 
-IRInstruction subclass: #IRClosure
-	instanceVariableNames: 'arguments'
+IRInstruction subclass: #IRScopedInstruction
+	instanceVariableNames: 'scope'
+	package: 'Compiler-IR'!
+
+!IRScopedInstruction methodsFor: 'accessing'!
+
+scope
+	^ scope
+!
+
+scope: aScope
+	aScope instruction: self.
+	scope := aScope
+! !
+
+IRScopedInstruction subclass: #IRClosure
+	instanceVariableNames: 'arguments inlined'
 	package: 'Compiler-IR'!
 
 !IRClosure methodsFor: 'accessing'!
@@ -368,14 +457,24 @@ arguments
 
 arguments: aCollection
 	arguments := aCollection
+!
+
+inlined
+	^ inlined ifNil: [ false ]
+!
+
+inlined: aBoolean
+	inlined := aBoolean
 ! !
 
-!IRClosure methodsFor: 'emiting'!
+!IRClosure methodsFor: 'testing'!
 
-emitOn: aStream
-	aStream 
-		nextPutClosureWith: [ super emitOn: aStream ] 
-		arguments: self arguments
+isClosure
+	^ true
+!
+
+isInlined
+	^ self inlined
 ! !
 
 !IRClosure methodsFor: 'visiting'!
@@ -384,8 +483,8 @@ accept: aVisitor
 	aVisitor visitIRClosure: self
 ! !
 
-IRInstruction subclass: #IRMethod
-	instanceVariableNames: 'source selector classReferences messageSends arguments internalVariables source'
+IRScopedInstruction subclass: #IRMethod
+	instanceVariableNames: 'source selector classReferences messageSends arguments internalVariables'
 	package: 'Compiler-IR'!
 !IRMethod commentStamp!
 I am a method instruction!
@@ -436,102 +535,34 @@ source: aString
 	source := aString
 ! !
 
-!IRMethod methodsFor: 'emiting'!
+!IRMethod methodsFor: 'visiting'!
 
 accept: aVisitor
 	aVisitor visitIRMethod: self
-!
-
-emitOn: aStream
-	aStream
-		nextPutMethodDeclaration: self 
-		with: [
-			aStream 
-				nextPutFunctionWith: [ 
-					self internalVariables notEmpty ifTrue: [
-						aStream nextPutVars: self internalVariables ].
-					super emitOn: aStream ]
-			arguments: self arguments ]
-! !
-
-IRInstruction subclass: #IRNonLocalReturn
-	instanceVariableNames: ''
-	package: 'Compiler-IR'!
-!IRNonLocalReturn commentStamp!
-I am a non local return instruction.
-Non local returns are handled using a try/catch JS statement.
-
-See IRNonLocalReturnHandling class!
-
-!IRNonLocalReturn methodsFor: 'emiting'!
-
-emitOn: aStream
-	aStream nextPutNonLocalReturnWith: [
-		super emitOn: aStream ]
-! !
-
-!IRNonLocalReturn methodsFor: 'visiting'!
-
-accept: aVisitor
-	aVisitor visitIRNonLocalReturn: self
-! !
-
-IRInstruction subclass: #IRNonLocalReturnHandling
-	instanceVariableNames: ''
-	package: 'Compiler-IR'!
-!IRNonLocalReturnHandling commentStamp!
-I represent a non local return handling instruction.
-Non local returns are handled with a try/catch statement!
-
-!IRNonLocalReturnHandling methodsFor: 'emiting'!
-
-emitOn: aStream
-	aStream nextPutNonLocalReturnHandlingWith: [
-		super emitOn: aStream ]
-! !
-
-!IRNonLocalReturnHandling methodsFor: 'visiting'!
-
-accept: aVisitor
-	aVisitor visitIRNonLocalReturnHandling: self
-! !
-
-IRInstruction subclass: #IRReturn
-	instanceVariableNames: ''
-	package: 'Compiler-IR'!
-!IRReturn commentStamp!
-I am a local return instruction.!
-
-!IRReturn methodsFor: 'emiting'!
-
-emitOn: aStream
-	aStream nextPutReturnWith: [
-		super emitOn: aStream ]
-! !
-
-!IRReturn methodsFor: 'visiting'!
-
-accept: aVisitor
-	aVisitor visitIRReturn: self
 ! !
 
 IRInstruction subclass: #IRSend
-	instanceVariableNames: 'selector superSend'
+	instanceVariableNames: 'selector classSend inlined'
 	package: 'Compiler-IR'!
 !IRSend commentStamp!
 I am a message send instruction.!
 
 !IRSend methodsFor: 'accessing'!
 
-emitOn: aStream
+classSend
+	^ classSend
+!
+
+classSend: aClass
+	classSend := aClass
+!
+
+inlined
+	^ inlined ifNil: [ false ]
+!
 
-	aStream nextPutAll: 'smalltalk.send('.
-	self instructions first emitOn: aStream.
-	aStream nextPutAll:  ',"', self selector asSelector, '", ['.
-	self instructions allButFirst
-		do: [ :each | each emitOn: aStream ]
-		separatedBy: [ aStream nextPutAll: ',' ].
-	aStream nextPutAll: '])'
+inlined: aBoolean
+	inlined := aBoolean
 !
 
 selector
@@ -540,14 +571,12 @@ selector
 
 selector: aString
 	selector := aString
-!
+! !
 
-superSend
-	^ superSend ifNil: [ false ]
-!
+!IRSend methodsFor: 'testing'!
 
-superSend: aBoolean
-	superSend := aBoolean
+isInlined
+	^ self inlined
 ! !
 
 !IRSend methodsFor: 'visiting'!
@@ -560,20 +589,10 @@ IRInstruction subclass: #IRSequence
 	instanceVariableNames: ''
 	package: 'Compiler-IR'!
 
-!IRSequence methodsFor: 'emiting'!
+!IRSequence methodsFor: 'adding'!
 
 appendInstruction: anIRInstruction
 	self instructions add: ((IRStatement on: self builder) with: anIRInstruction)
-!
-
-emitOn: aStream
-	aStream nextPutSequenceWith: [
-		"self instructions do: [ :each |
-			((IRStatement on: self builder)
-				pc: self builder nextPc;
-				with: each;
-				yourself) emitOn: aStream ]"
-		super emitOn: aStream ]
 ! !
 
 !IRSequence methodsFor: 'visiting'!
@@ -582,6 +601,16 @@ accept: aVisitor
 	aVisitor visitIRSequence: self
 ! !
 
+IRSequence subclass: #IRBlockSequence
+	instanceVariableNames: ''
+	package: 'Compiler-IR'!
+
+!IRBlockSequence methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRBlockSequence: self
+! !
+
 IRInstruction subclass: #IRStatement
 	instanceVariableNames: 'pc'
 	package: 'Compiler-IR'!
@@ -595,13 +624,6 @@ pc
 	^ pc ifNil: [pc := self builder nextPc]
 ! !
 
-!IRStatement methodsFor: 'emiting'!
-
-emitOn: aStream
-	aStream nextPutStatement: self pc with: [
-		super emitOn: aStream ]
-! !
-
 !IRStatement methodsFor: 'visiting'!
 
 accept: aVisitor
@@ -624,12 +646,6 @@ name: aString
 	name := aString
 ! !
 
-!IRTempDeclaration methodsFor: 'emiting'!
-
-emitOn: aStream
-	aStream nextPutVar: self name asVariableName
-! !
-
 !IRTempDeclaration methodsFor: 'visiting'!
 
 accept: aVisitor
@@ -646,22 +662,16 @@ I am the simplest possible instruction. I represent a value.!
 
 value
 	^value
-! !
-
-!IRValue methodsFor: 'emiting'!
-
-accept: aVisitor
-	aVisitor visitIRValue: self
 !
 
-emitOn: aStream
-	aStream nextPutAll: self value asJavascript
+value: aString
+	value := aString
 ! !
 
 !IRValue methodsFor: 'visiting'!
 
-value: aString
-	value := aString
+accept: aVisitor
+	aVisitor visitIRValue: self
 ! !
 
 IRInstruction subclass: #IRVariable
@@ -680,18 +690,12 @@ variable: aScopeVariable
 	variable := aScopeVariable
 ! !
 
-!IRVariable methodsFor: 'emiting'!
+!IRVariable methodsFor: 'visiting'!
 
 accept: aVisitor
 	aVisitor visitIRVariable: self
 ! !
 
-!IRVariable methodsFor: 'visiting'!
-
-emitOn: aStream
-	aStream nextPutAll: self variable alias
-! !
-
 IRInstruction subclass: #IRVerbatim
 	instanceVariableNames: 'source'
 	package: 'Compiler-IR'!
@@ -706,12 +710,6 @@ source: aString
 	source := aString
 ! !
 
-!IRVerbatim methodsFor: 'emiting'!
-
-emitOn: aStream
-	aStream nextPutAll: self source, ';'
-! !
-
 !IRVerbatim methodsFor: 'visiting'!
 
 accept: aVisitor
@@ -728,10 +726,18 @@ visit: anIRInstruction
 	anIRInstruction accept: self
 !
 
+visitIRAlias: anIRAlias
+	self visitIRAssignment: anIRAlias
+!
+
 visitIRAssignment: anIRAssignment
 	self visitIRInstruction: anIRAssignment
 !
 
+visitIRBlockSequence: anIRBlockSequence
+	self visitIRSequence: anIRBlockSequence
+!
+
 visitIRClosure: anIRClosure
 	self visitIRInstruction: anIRClosure
 !
@@ -788,6 +794,20 @@ IRVisitor subclass: #IRJSTranslator
 	instanceVariableNames: 'stream'
 	package: 'Compiler-IR'!
 
+!IRJSTranslator methodsFor: 'accessing'!
+
+contents
+	^ self stream contents
+!
+
+stream
+	^ stream
+!
+
+stream: aStream
+	stream := aStream
+! !
+
 !IRJSTranslator methodsFor: 'initialization'!
 
 initialize
@@ -795,6 +815,100 @@ initialize
 	stream := JSStream new.
 ! !
 
+!IRJSTranslator methodsFor: 'visiting'!
+
+visitIRAssignment: anIRAssignment
+	self visit: anIRAssignment instructions first.
+	self stream nextPutAssignment.
+	self visit: anIRAssignment instructions last.
+!
+
+visitIRBlockSequence: anIRBlockSequence
+	self stream nextPutSequenceWith: [
+		anIRBlockSequence instructions notEmpty ifTrue: [
+			anIRBlockSequence instructions allButLast do: [ :each | 
+				self visit: each ].
+			self stream nextPutReturn.
+			self visit: anIRBlockSequence instructions last ]]
+!
+
+visitIRClosure: anIRClosure
+	self stream 
+		nextPutClosureWith: [ super visitIRClosure: anIRClosure ] 
+		arguments: anIRClosure arguments
+!
+
+visitIRMethod: anIRMethod
+	self stream
+		nextPutMethodDeclaration: anIRMethod 
+		with: [ self stream 
+			nextPutFunctionWith: [ 
+				anIRMethod internalVariables notEmpty ifTrue: [
+					self stream nextPutVars: anIRMethod internalVariables ].
+				super visitIRMethod: anIRMethod ]
+			arguments: anIRMethod arguments ]
+!
+
+visitIRNonLocalReturn: anIRNonLocalReturn
+	self stream nextPutNonLocalReturnWith: [
+		super visitIRNonLocalReturn: anIRNonLocalReturn ]
+!
+
+visitIRNonLocalReturnHandling: anIRNonLocalReturnHandling
+	self stream nextPutNonLocalReturnHandlingWith: [
+		super visitIRNonLocalReturnHandling: anIRNonLocalReturnHandling ]
+!
+
+visitIRReturn: anIRReturn
+	self stream nextPutReturnWith: [
+		super visitIRReturn: anIRReturn ]
+!
+
+visitIRSend: anIRSend
+	self stream nextPutAll: 'smalltalk.send('.
+	self visit: anIRSend instructions first.
+	self stream nextPutAll:  ',"', anIRSend selector asSelector, '",['.
+	anIRSend instructions allButFirst
+		do: [ :each | self visit: each ]
+		separatedBy: [ self stream nextPutAll: ',' ].
+	self stream nextPutAll: ']'.
+	anIRSend classSend ifNotNil: [  
+		self stream nextPutAll: ',', anIRSend classSend asJavascript ].
+	self stream nextPutAll: ')'
+!
+
+visitIRSequence: anIRSequence
+	self stream nextPutSequenceWith: [
+		"self instructions do: [ :each |
+			((IRStatement on: self builder)
+				pc: self builder nextPc;
+				with: each;
+				yourself) emitOn: aStream ]"
+		super visitIRSequence: anIRSequence ]
+!
+
+visitIRStatement: anIRStatement
+	self stream nextPutStatementWith: [
+		super visitIRStatement: anIRStatement ]
+!
+
+visitIRTempDeclaration: anIRTempDeclaration
+	self stream nextPutVar: anIRTempDeclaration name asVariableName
+!
+
+visitIRValue: anIRValue
+	self stream nextPutAll: anIRValue value asJavascript
+!
+
+visitIRVariable: anIRVariable
+	self stream nextPutAll: anIRVariable variable alias
+!
+
+visitIRVerbatim: anIRVerbatim
+	self stream nextPutStatementWith: [
+		self stream nextPutAll: anIRVerbatim source ]
+! !
+
 Object subclass: #JSStream
 	instanceVariableNames: 'stream'
 	package: 'Compiler-IR'!
@@ -826,10 +940,8 @@ nextPutAll: aString
 	stream nextPutAll: aString
 !
 
-nextPutAssignment: varInstruction to: valueInstruction
-	varInstruction emitOn: self.
-	stream nextPutAll: '='.
-	valueInstruction emitOn: self
+nextPutAssignment
+	stream nextPutAll: '='
 !
 
 nextPutClosureWith: aBlock arguments: anArray
@@ -850,7 +962,7 @@ nextPutFunctionWith: aBlock arguments: anArray
 	stream nextPutAll: '){'; lf.
 	stream nextPutAll: 'var self=this;'; lf.
 	aBlock value.
-	stream nextPutAll: 'return self;}'
+	stream nextPutAll: '}'
 !
 
 nextPutMethodDeclaration: aMethod with: aBlock
@@ -888,8 +1000,12 @@ nextPutNonLocalReturnWith: aBlock
 	stream nextPutAll: ']})()'
 !
 
+nextPutReturn
+	stream nextPutAll: 'return '
+!
+
 nextPutReturnWith: aBlock
-	stream nextPutAll: 'return '.
+	self nextPutReturn.
 	aBlock value
 !
 
@@ -912,12 +1028,14 @@ nextPutSequenceWith: aBlock
 !
 
 nextPutStatement: anInteger with: aBlock
-	"stream 
-		nextPutAll: 'case ', anInteger asString, ':'; lf."
+	stream nextPutAll: 'case ', anInteger asString, ':'; lf.
+	self nextPutStatementWith: aBlock.
+	stream nextPutAll: 'smalltalk.thisContext.pc=', (anInteger + 1) asString, ';'; lf
+!
+
+nextPutStatementWith: aBlock
 	aBlock value.
-	stream 
-		nextPutAll: ';'; lf";
-		nextPutAll: 'smalltalk.thisContext.pc=', (anInteger + 1) asString, ';'; lf"
+	stream nextPutAll: ';'; lf
 !
 
 nextPutVar: aString

+ 94 - 23
st/Compiler-Semantic.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-Semantic' properties: #{}!
 Object subclass: #LexicalScope
-	instanceVariableNames: 'node temps args outerScope'
+	instanceVariableNames: 'node instruction temps args outerScope'
 	package: 'Compiler-Semantic'!
 !LexicalScope commentStamp!
 I represent a lexical scope where variable names are associated with ScopeVars
@@ -20,8 +20,17 @@ args
 !
 
 bindingFor: aStringOrNode
-	^ self args at: aStringOrNode value ifAbsent: [
-		self temps at: aStringOrNode value ifAbsent: [ nil ]]
+	^ self pseudoVars at: aStringOrNode value ifAbsent: [ 
+		self args at: aStringOrNode value ifAbsent: [
+			self temps at: aStringOrNode value ifAbsent: [ nil ]]]
+!
+
+instruction
+	^ instruction
+!
+
+instruction: anIRInstruction
+	instruction := anIRInstruction
 !
 
 lookupVariable: aNode
@@ -56,6 +65,10 @@ outerScope: aLexicalScope
 	outerScope := aLexicalScope
 !
 
+pseudoVars
+	^ self methodScope pseudoVars
+!
+
 scopeLevel
 	^ (self outerScope 
 		ifNil: [ 0 ]
@@ -85,7 +98,7 @@ isMethodScope
 ! !
 
 LexicalScope subclass: #MethodLexicalScope
-	instanceVariableNames: 'iVars unknownVariables nonLocalReturn'
+	instanceVariableNames: 'iVars unknownVariables localReturn nonLocalReturn'
 	package: 'Compiler-Semantic'!
 !MethodLexicalScope commentStamp!
 I represent a method scope.!
@@ -105,6 +118,14 @@ iVars
 	^ iVars ifNil: [ iVars := Dictionary new ]
 !
 
+localReturn
+	^ localReturn ifNil: [ false ]
+!
+
+localReturn: aBoolean
+	localReturn := aBoolean
+!
+
 methodScope
 	^ self
 !
@@ -117,19 +138,33 @@ nonLocalReturn: aBoolean
 	nonLocalReturn := aBoolean
 !
 
+pseudoVars
+	pseudoVars ifNil: [
+		pseudoVars := Dictionary new.
+		Smalltalk current pseudoVariableNames do: [ :each |
+			pseudoVars at: each put: ((PseudoVar on: each)
+				scope: self methodScope;
+				yourself) ]].
+	^ pseudoVars
+!
+
 unknownVariables
 	^ unknownVariables ifNil: [ unknownVariables := OrderedCollection new ]
 ! !
 
 !MethodLexicalScope methodsFor: 'adding'!
 
-addIvar: aString
+addIVar: aString
 	self iVars at: aString put: (InstanceVar on: aString).
 	(self iVars at: aString) scope: self
 ! !
 
 !MethodLexicalScope methodsFor: 'testing'!
 
+hasLocalReturn
+	^ self localReturn
+!
+
 hasNonLocalReturn
 	^ self nonLocalReturn
 !
@@ -173,16 +208,31 @@ isArgVar
 	^ false
 !
 
+isClassRefVar
+	^ false
+!
+
 isInstanceVar
 	^ false
 !
 
+isPseudoVar
+	^ false
+!
+
 isTempVar
 	^ false
 !
 
 isUnknownVar
 	^ false
+!
+
+validateAssignment
+	(self isArgVar or: [ self isPseudoVar ]) ifTrue: [
+		InvalidAssignmentError new
+			variableName: self name;
+			signal]
 ! !
 
 !ScopeVar class methodsFor: 'instance creation'!
@@ -230,7 +280,13 @@ I am an class reference variable!
 !ClassRefVar methodsFor: 'accessing'!
 
 alias
-	^ '(Smalltalk.', self name, ' || ', self name, ')'
+	^ '(smalltalk.', self name, ' || ', self name, ')'
+! !
+
+!ClassRefVar methodsFor: 'testing'!
+
+isClassRefVar
+	^ true
 ! !
 
 ScopeVar subclass: #InstanceVar
@@ -242,13 +298,33 @@ I am an instance variable of a method or block.!
 !InstanceVar methodsFor: 'testing'!
 
 alias
-	^ 'self["@', self name, ']'
+	^ 'self["@', self name, '"]'
 !
 
 isInstanceVar
 	^ true
 ! !
 
+ScopeVar subclass: #PseudoVar
+	instanceVariableNames: ''
+	package: 'Compiler-Semantic'!
+!PseudoVar commentStamp!
+I am an pseudo variable.
+
+The five Smalltalk pseudo variables are: 'self', 'super', 'nil', 'true' and 'false'!
+
+!PseudoVar methodsFor: 'accessing'!
+
+alias
+	^ self name
+! !
+
+!PseudoVar methodsFor: 'testing'!
+
+isPseudoVar
+	^ true
+! !
+
 ScopeVar subclass: #TempVar
 	instanceVariableNames: ''
 	package: 'Compiler-Semantic'!
@@ -303,12 +379,6 @@ theClass: aClass
 
 !SemanticAnalyzer methodsFor: 'error handling'!
 
-errorInvalidAssignment: aString
-	InvalidAssignmentError new
-		variableName: aString;
-		signal
-!
-
 errorShadowingVariable: aString
 	ShadowingVariableError new
 		variableName: aString;
@@ -369,12 +439,8 @@ allowUnknownVariables
 
 visitAssignmentNode: aNode
 	super visitAssignmentNode: aNode.
-	(self pseudoVariables includes: aNode left value) ifTrue: [
-		self errorInvalidAssignment: aNode left value ].
-	aNode left binding isArgVar ifTrue: [
-		self errorInvalidAssignment: aNode left value ].
 	aNode left beAssigned.
-	aNode right beUsed.
+	aNode right beUsed
 !
 
 visitBlockNode: aNode
@@ -391,8 +457,11 @@ visitBlockNode: aNode
 
 visitCascadeNode: aNode
 	"Populate the receiver into all children"
-	aNode nodes do: [ :each | each receiver: aNode receiver ].
-	super visitCascadeNode: aNode
+	aNode nodes do: [ :each | 
+		each receiver: aNode receiver ].
+	super visitCascadeNode: aNode.
+	aNode nodes first superSend ifTrue: [
+		aNode nodes do: [ :each | each superSend: true ]]
 !
 
 visitClassReferenceNode: aNode
@@ -419,9 +488,11 @@ visitMethodNode: aNode
 !
 
 visitReturnNode: aNode
-	currentScope isMethodScope ifFalse: [
-		currentScope methodScope nonLocalReturn: true.
-		aNode nonLocalReturn: true ].
+	currentScope isMethodScope 
+		ifTrue: [ currentScope localReturn: true ]
+		ifFalse: [
+			currentScope methodScope nonLocalReturn: true.
+			aNode nonLocalReturn: true ].
 	aNode nodes first beUsed.
 	super visitReturnNode: aNode
 !

+ 62 - 0
st/Compiler-Tests.st

@@ -1,4 +1,66 @@
 Smalltalk current createPackage: 'Compiler-Tests' properties: #{}!
+TestCase subclass: #IRASTTranslatorTest
+	instanceVariableNames: ''
+	package: 'Compiler-Tests'!
+
+!IRASTTranslatorTest methodsFor: 'tests'!
+
+testIRMethod
+! !
+
+TestCase subclass: #ScopeVarTest
+	instanceVariableNames: ''
+	package: 'Compiler-Tests'!
+
+!ScopeVarTest methodsFor: 'tests'!
+
+testClassRefVar
+	| node |
+	node := ClassReferenceNode new
+		value: 'Object';
+		yourself.
+	SemanticAnalyzer new visit: node.
+	self assert: node binding isClassRefVar
+!
+
+testInstanceVar
+	| node scope |
+	node := VariableNode new
+		value: 'bzzz';
+		yourself.
+	scope := MethodLexicalScope new.
+	scope addIVar: 'bzzz'.
+	self assert: (scope bindingFor: node) isInstanceVar
+!
+
+testPseudoVar
+	| node pseudoVars |
+	pseudoVars := #('self' 'super' 'true' 'false' 'nil').
+	pseudoVars do: [:each |
+		node := VariableNode new
+		value: each;
+		yourself.
+		self assert: (MethodLexicalScope new bindingFor: node) isPseudoVar ]
+!
+
+testTempVar
+	| node scope |
+	node := VariableNode new
+		value: 'bzzz';
+		yourself.
+	scope := MethodLexicalScope new.
+	scope addTemp: 'bzzz'.
+	self assert: (scope bindingFor: node) isTempVar
+!
+
+testUnknownVar
+	| node |
+	node := VariableNode new
+		value: 'bzzz';
+		yourself.
+	self assert: (MethodLexicalScope new bindingFor: node) isNil
+! !
+
 TestCase subclass: #SemanticAnalyzerTest
 	instanceVariableNames: 'analyzer'
 	package: 'Compiler-Tests'!

+ 0 - 696
st/Compiler-Visitors.st

@@ -1,696 +0,0 @@
-Smalltalk current createPackage: 'Compiler-Visitors' properties: #{}!
-AbstractCodeGenerator subclass: #ImpCodeGenerator
-	instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables mutables target lazyVars realVarNames'
-	package: 'Compiler-Visitors'!
-
-!ImpCodeGenerator methodsFor: 'accessing'!
-
-argVariables
-	^argVariables copy
-!
-
-knownVariables
-	^self pseudoVariables 
-		addAll: self tempVariables;
-		addAll: self argVariables;
-		yourself
-!
-
-tempVariables
-	^tempVariables copy
-!
-
-unknownVariables
-	^unknownVariables copy
-! !
-
-!ImpCodeGenerator methodsFor: 'compilation DSL'!
-
-aboutToModifyState
-| list old |
-	list := mutables.
-	mutables := Set new.
-	old := self switchTarget: nil.
-	list do: [ :each | | value |
-		self switchTarget: each.
-		self realAssign: (lazyVars at: each)
-	].
-	self switchTarget: old
-!
-
-ifValueWanted: aBlock
-	target ifNotNil: aBlock
-!
-
-isolated: node
- 	^ self visit: node targetBeing: self nextLazyvarName
-!
-
-isolatedUse: node
-| old |
-	old := self switchTarget: self nextLazyvarName.
-	self visit: node.
-	^self useValueNamed: (self switchTarget: old)
-!
-
-lazyAssign: aString dependsOnState: aBoolean
-	(lazyVars includesKey: target)
-		ifTrue: [ lazyVars at: target put: aString. aBoolean ifTrue: [ mutables add: target ] ]
-		ifFalse: [ self realAssign: aString ]
-!
-
-lazyAssignExpression: aString
-	self lazyAssign: aString dependsOnState: true
-!
-
-lazyAssignValue: aString
-	self lazyAssign: aString dependsOnState: false
-!
-
-makeTargetRealVariable
-	(lazyVars includesKey: target) ifTrue: [
-		lazyVars removeKey: target.
-		lazyVars at: 'assigned ',target put: nil. "<-- only to retain size, it is used in nextLazyvarName"
-		realVarNames add: target ].
-!
-
-nextLazyvarName
-	| name |
-	name := '$', lazyVars size asString.
-	lazyVars at: name put: name.
-	^name
-!
-
-nilIfValueWanted
-	target ifNotNil: [ self lazyAssignValue: 'nil' ]
-!
-
-realAssign: aString
-	| closer |
-	aString ifNotEmpty: [
-		self aboutToModifyState.
-		closer := ''.
-		self ifValueWanted: [ stream nextPutAll:
-			(target = '^' ifTrue: ['return '] ifFalse: [
-				target = '!!' ifTrue: [ closer := ']'. 'throw $early=['] ifFalse: [
-					target, '=']]) ].
-		self makeTargetRealVariable.
-		stream nextPutAll: aString, closer, ';', self mylf ]
-!
-
-switchTarget: aString
-	| old |
-	old := target.
-	target := aString.
-	^old
-!
-
-useValueNamed: key
-	| val |
-	(realVarNames includes: key) ifTrue: [ ^key ].
-	mutables remove: key.
-	^lazyVars at: key
-!
-
-visit: aNode targetBeing: aString
-| old |
-	old := self switchTarget: aString.
-	self visit: aNode.
-	^ self switchTarget: old.
-! !
-
-!ImpCodeGenerator methodsFor: 'compiling'!
-
-compileNode: aNode
-	stream := '' writeStream.
-	self visit: aNode.
-	^stream contents
-! !
-
-!ImpCodeGenerator methodsFor: 'initialization'!
-
-initialize
-	super initialize.
-	stream := '' writeStream. 
-	unknownVariables := #().
-	tempVariables := #().
-	argVariables := #().
-	messageSends := #().
-	classReferenced := #().
-	mutables := Set new.
-	realVarNames := Set new.
-	lazyVars := HashedCollection new.
-	target := nil
-! !
-
-!ImpCodeGenerator methodsFor: 'optimizations'!
-
-checkClass: aClassName for: receiver
-	self prvCheckClass: aClassName for: receiver.
-	stream nextPutAll: '{'
-!
-
-checkClass: aClassName for: receiver includeIf: aBoolean
-	self prvCheckClass: aClassName for: receiver.
-	stream nextPutAll: (aBoolean ifTrue: ['if(('] ifFalse: ['if(!!(']), (self useValueNamed: receiver), ')) {'
-!
-
-inline: aSelector receiver: receiver argumentNodes: aCollection
-
-	"-- Booleans --"
-
-	(aSelector = 'ifFalse:') ifTrue: [
-		aCollection first isBlockNode ifTrue: [
-			self checkClass: 'Boolean' for: receiver includeIf: false.
-			self prvPutAndElse: [ self visit: aCollection first nodes first ].
-			self prvPutAndElse: [ self nilIfValueWanted ].
-			^true]].
-
-	(aSelector = 'ifTrue:') ifTrue: [
-		aCollection first isBlockNode ifTrue: [
-			self checkClass: 'Boolean' for: receiver includeIf: true.
-			self prvPutAndElse: [ self visit: aCollection first nodes first ].
-			self prvPutAndElse: [ self nilIfValueWanted ].
-			^true]].
-
-	(aSelector = 'ifTrue:ifFalse:') ifTrue: [
-		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
-			self checkClass: 'Boolean' for: receiver includeIf: true.
-			self prvPutAndElse: [ self visit: aCollection first nodes first ].
-			self prvPutAndElse: [ self visit: aCollection second nodes first ].
-			^true]].
-
-	(aSelector = 'ifFalse:ifTrue:') ifTrue: [
-		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
-			self checkClass: 'Boolean' for: receiver includeIf: false.
-			self prvPutAndElse: [ self visit: aCollection first nodes first ].
-			self prvPutAndElse: [ self visit: aCollection second nodes first ].
-			^true]].
-
-	"-- Numbers --"
-
-	(aSelector = '<') ifTrue: [ | operand |
-		operand := self isolatedUse: aCollection first.
-		self checkClass: 'Number' for: receiver.
-		self prvPutAndElse: [
-			self lazyAssignExpression: '(', (self useValueNamed: receiver), '<', operand, ')' ].
-		^{ VerbatimNode new value: operand }].
-
-	(aSelector = '<=') ifTrue: [ | operand |
-		operand := self isolatedUse: aCollection first.
-		self checkClass: 'Number' for: receiver.
-		self prvPutAndElse: [
-			self lazyAssignExpression: '(', (self useValueNamed: receiver), '<=', operand, ')' ].
-		^{ VerbatimNode new value: operand }].
-
-	(aSelector = '>') ifTrue: [ | operand |
-		operand := self isolatedUse: aCollection first.
-		self checkClass: 'Number' for: receiver.
-		self prvPutAndElse: [
-			self lazyAssignExpression: '(', (self useValueNamed: receiver), '>', operand, ')' ].
-		^{ VerbatimNode new value: operand }].
-
-	(aSelector = '>=') ifTrue: [ | operand |
-		operand := self isolatedUse: aCollection first.
-		self checkClass: 'Number' for: receiver.
-		self prvPutAndElse: [
-			self lazyAssignExpression: '(', (self useValueNamed: receiver), '>=', operand, ')' ].
-		^{ VerbatimNode new value: operand }].
-
-        (aSelector = '+') ifTrue: [ | operand |
-		operand := self isolatedUse: aCollection first.
-		self checkClass: 'Number' for: receiver.
-		self prvPutAndElse: [
-			self lazyAssignExpression: '(', (self useValueNamed: receiver), '+', operand, ')' ].
-		^{ VerbatimNode new value: operand }].
-
-        (aSelector = '-') ifTrue: [ | operand |
-		operand := self isolatedUse: aCollection first.
-		self checkClass: 'Number' for: receiver.
-		self prvPutAndElse: [
-			self lazyAssignExpression: '(', (self useValueNamed: receiver), '-', operand, ')' ].
-		^{ VerbatimNode new value: operand }].
-
-        (aSelector = '*') ifTrue: [ | operand |
-		operand := self isolatedUse: aCollection first.
-		self checkClass: 'Number' for: receiver.
-		self prvPutAndElse: [
-			self lazyAssignExpression: '(', (self useValueNamed: receiver), '*', operand, ')' ].
-		^{ VerbatimNode new value: operand }].
-
-        (aSelector = '/') ifTrue: [ | operand |
-		operand := self isolatedUse: aCollection first.
-		self checkClass: 'Number' for: receiver.
-		self prvPutAndElse: [
-			self lazyAssignExpression: '(', (self useValueNamed: receiver), '/', operand, ')' ].
-		^{ VerbatimNode new value: operand }].
-
-        ^nil
-!
-
-inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
-        | inlined |
-        inlined := false.
- 
-	"-- BlockClosures --"
-
-	(aSelector = 'whileTrue:') ifTrue: [
-          	(anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [ | old |
-			self prvWhileConditionStatement: 'for(;;){' pre: 'if (!!(' condition: anObject post: ')) {'.
-			stream nextPutAll: 'break}', self mylf.
-			self prvPutAndClose: [ self visit: aCollection first nodes first targetBeing: nil ].
-			inlined := true]].
-
-	(aSelector = 'whileFalse:') ifTrue: [
-          	(anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [ | old |
-			self prvWhileConditionStatement: 'for(;;){' pre: 'if ((' condition: anObject post: ')) {'.
-			stream nextPutAll: 'break}', self mylf.
-			self prvPutAndClose: [ self visit: aCollection first nodes first targetBeing: nil ].
-			inlined := true]].
-
-	(aSelector = 'whileTrue') ifTrue: [
-          	anObject isBlockNode ifTrue: [
-			self prvWhileConditionStatement: 'do{' pre: '}while((' condition: anObject post: '));', self mylf.
-			inlined := true]].
-
-	(aSelector = 'whileFalse') ifTrue: [
-          	anObject isBlockNode ifTrue: [
-			self prvWhileConditionStatement: 'do{' pre: '}while(!!(' condition: anObject post: '));', self mylf.
-			inlined := true]].
-
-	"-- Numbers --"
-
-	(#('+' '-' '*' '/' '<' '<=' '>=' '>') includes: aSelector) ifTrue: [
-		(self prvInlineNumberOperator: aSelector on: anObject and: aCollection first) ifTrue: [
-			inlined := true]].
-                	   
-	"-- UndefinedObject --"
-
-	(aSelector = 'ifNil:') ifTrue: [
-		aCollection first isBlockNode ifTrue: [ | rcv |
-			self aboutToModifyState.
-			rcv := self isolatedUse: anObject.
-			rcv = 'super' ifTrue: [ rcv := 'self' ].
-			self makeTargetRealVariable.
-			stream nextPutAll: 'if((', rcv, ') === nil || (', rcv, ') == null) {'.
-			self prvPutAndElse: [ self visit: aCollection first nodes first ].
-			self prvPutAndClose: [ self lazyAssignValue: rcv ].
-			inlined := true]].
-
-	(aSelector = 'ifNotNil:') ifTrue: [
-		aCollection first isBlockNode ifTrue: [ | rcv |
-			self aboutToModifyState.
-			rcv := self isolatedUse: anObject.
-			rcv = 'super' ifTrue: [ rcv := 'self' ].
-			self makeTargetRealVariable.
-			stream nextPutAll: 'if((', rcv, ') !!== nil && (', rcv, ') !!= null) {'.
-			self prvPutAndElse: [ self visit: aCollection first nodes first ].
-			self prvPutAndClose: [ self lazyAssignValue: rcv ].
-			inlined := true]].
-
-	(aSelector = 'ifNil:ifNotNil:') ifTrue: [
-		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [ | rcv |
-			self aboutToModifyState.
-			rcv := self isolatedUse: anObject.
-			rcv = 'super' ifTrue: [ rcv := 'self' ].
-			self makeTargetRealVariable.
-			stream nextPutAll: 'if((', rcv, ') === nil || (', rcv, ') == null) {'.
-			self prvPutAndElse: [ self visit: aCollection first nodes first ].
-			self prvPutAndClose: [ self visit: aCollection second nodes first ].
-			inlined := true]].
-
-	(aSelector = 'ifNotNil:ifNil:') ifTrue: [
-		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [ | rcv |
-			self aboutToModifyState.
-			rcv := self isolatedUse: anObject.
-			rcv = 'super' ifTrue: [ rcv := 'self' ].
-			self makeTargetRealVariable.
-			stream nextPutAll: 'if((', rcv, ') !!== nil && (', rcv, ') !!= null) {'.
-			self prvPutAndElse: [ self visit: aCollection first nodes first ].
-			self prvPutAndClose: [ self visit: aCollection second nodes first ].
-			inlined := true]].
-
-	(aSelector = 'isNil') ifTrue: [ | rcv |
-		rcv := self isolatedUse: anObject.
-		rcv = 'super' ifTrue: [ rcv := 'self' ].
-		self lazyAssignValue: '((', rcv, ') === nil || (', rcv, ') == null)'.
-		inlined := true].
-
-	(aSelector = 'notNil') ifTrue: [ | rcv |
-		rcv := self isolatedUse: anObject.
-		rcv = 'super' ifTrue: [ rcv := 'self' ].
-		self lazyAssignValue: '((', rcv, ') !!== nil && (', rcv, ') !!= null)'.
-		inlined := true].
-
-        ^inlined
-!
-
-isNode: aNode ofClass: aClass
-	^aNode isValueNode and: [
-          	aNode value class = aClass or: [
-          		aNode value = 'self' and: [self currentClass = aClass]]]
-!
-
-prvCheckClass: aClassName for: receiver
-	self makeTargetRealVariable.
-	self aboutToModifyState.
-        stream nextPutAll: 'if((', (self useValueNamed: receiver), ').klass === smalltalk.', aClassName, ') '
-!
-
-prvInlineNumberOperator: aSelector on: receiverNode and: operandNode
-	(aSelector = aSelector) ifTrue: [
-		(self isNode: receiverNode ofClass: Number) ifTrue: [
-			| rcv operand |
-			rcv := self isolated: receiverNode.
-			operand := self isolated: operandNode.
-			self lazyAssignValue: ((self useValueNamed: rcv), aSelector, (self useValueNamed: operand)).
-			^true]].
-	^false
-!
-
-prvWhileConditionStatement: stmtString pre: preString condition: anObject post: postString
-	| x |
-	stream nextPutAll: stmtString.
-	x := self isolatedUse: anObject nodes first.
-	x ifEmpty: [ x := '"should not reach - receiver includes ^"' ].
-	stream nextPutAll: preString, x, postString.
-	self nilIfValueWanted
-! !
-
-!ImpCodeGenerator methodsFor: 'output'!
-
-mylf
-	^String lf, ((Array new: nestedBlocks+2)  join: String tab)
-!
-
-prvPutAndClose: aBlock
-
-	aBlock value.
-	stream nextPutAll: '}', self mylf
-!
-
-prvPutAndElse: aBlock
-
-	aBlock value.
-	stream nextPutAll: '} else {'
-!
-
-putTemps: temps
-    temps ifNotEmpty: [
-	stream nextPutAll: 'var '.
-	temps do: [:each | | temp |
-            temp := self safeVariableNameFor: each.
-	    tempVariables add: temp.
-	    stream nextPutAll: temp, '=nil'] separatedBy: [ stream nextPutAll: ',' ].
-	stream nextPutAll: ';', self mylf
-    ]
-! !
-
-!ImpCodeGenerator methodsFor: 'testing'!
-
-assert: aBoolean
-	aBoolean ifFalse: [ self error: 'assertion failed' ]
-!
-
-performOptimizations
-	^self class performOptimizations
-! !
-
-!ImpCodeGenerator methodsFor: 'visiting'!
-
-send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
-	| args |
-	args := self isolated: (DynamicArrayNode new nodes: aCollection; yourself).
-	self lazyAssignExpression: (String streamContents: [ :str |
-		str nextPutAll: 'smalltalk.send('.
-		str nextPutAll: (self useValueNamed: aReceiver).
-		str nextPutAll: ', "', aSelector asSelector, '", '.
-		str nextPutAll: (self useValueNamed: args).
-		aBoolean ifTrue: [
-			str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
-		str nextPutAll: ')'
-	])
-!
-
-sequenceOfNodes: nodes temps: temps
-	nodes isEmpty
-		ifFalse: [ | old index |
-			self putTemps: temps.
-			old :=self switchTarget: nil.
-			index := 0.
-			nodes do: [:each |
-				index := index + 1.
-				index = nodes size ifTrue: [ self switchTarget: old ].
-			self visit: each ]]
-		ifTrue: [ self nilIfValueWanted ]
-!
-
-visit: aNode
-	aNode accept: self
-!
-
-visitAssignmentNode: aNode
-| olds oldt |
-	olds := stream.
-	stream := '' writeStream.
-	oldt := self switchTarget: self nextLazyvarName.
-	self visit: aNode left.
-	self assert: (lazyVars at: target) ~= target.
-	self switchTarget: (self useValueNamed: (self switchTarget: nil)).
-	self assert: (lazyVars includesKey: target) not.
-	stream := olds.
-	self visit: aNode right.
-	olds := self switchTarget: oldt.
-	self ifValueWanted: [ self lazyAssignExpression: olds ]
-!
-
-visitBlockNode: aNode
-| oldt olds oldm |
-	self assert: aNode nodes size = 1.
-	oldt := self switchTarget: '^'.
-	olds := stream.
-	stream := '' writeStream.
-	stream nextPutAll: '(function('.
-	aNode parameters 
-	    do: [:each |
-		tempVariables add: each.
-		stream nextPutAll: each]
-	    separatedBy: [stream nextPutAll: ', '].
-	stream nextPutAll: '){'.
-	nestedBlocks := nestedBlocks + 1.
-	oldm := mutables.
-	mutables := Set new.
-	self visit: aNode nodes first.
-	self assert: mutables isEmpty.
-	mutables := oldm.
-	nestedBlocks := nestedBlocks - 1.
-	stream nextPutAll: '})'.
-	self switchTarget: oldt.
-	oldt := stream contents.
-	stream := olds.
-	self lazyAssignExpression: oldt
-!
-
-visitBlockSequenceNode: aNode
-	self sequenceOfNodes: aNode nodes temps: aNode temps
-!
-
-visitCascadeNode: aNode
-	| rcv |
-	rcv := self isolated: aNode receiver.
-	self aboutToModifyState.
-	rcv := self useValueNamed: rcv.
-	aNode nodes do: [:each |
-		each receiver: (VerbatimNode new value: rcv) ].
-	self sequenceOfNodes: aNode nodes temps: #()
-!
-
-visitClassReferenceNode: aNode
-	(referencedClasses includes: aNode value) ifFalse: [
-		referencedClasses add: aNode value].
-	self lazyAssignExpression: '(smalltalk.', aNode value, ' || ', aNode value, ')'
-!
-
-visitDynamicArrayNode: aNode
-	| args |
-	args :=aNode nodes collect: [ :node | self isolated: node ].
-	self lazyAssignValue: (String streamContents: [ :str |
-		str nextPutAll: '['.
-		args
-	    		do: [:each | str nextPutAll: (self useValueNamed: each) ]
-	    		separatedBy: [str nextPutAll: ', '].
-                str nextPutAll: ']'
-	])
-!
-
-visitDynamicDictionaryNode: aNode
-	| elements |
-	elements := self isolated: (DynamicArrayNode new nodes: aNode nodes; yourself).
-	self lazyAssignValue: 'smalltalk.HashedCollection._fromPairs_(', (self useValueNamed: elements), ')'
-!
-
-visitFailure: aFailure
-	self error: aFailure asString
-!
-
-visitJSStatementNode: aNode
-	self aboutToModifyState.
-	stream nextPutAll: ';', (aNode source replace: '>>' with: '>'), ';', self mylf
-!
-
-visitMethodNode: aNode
-	| str currentSelector | 
-	currentSelector := aNode selector asSelector.
-	nestedBlocks := 0.
-	earlyReturn := false.
-	messageSends := #().
-	referencedClasses := #().
-	unknownVariables := #().
-	tempVariables := #().
-	argVariables := #().
-	lazyVars := HashedCollection new.
-	mutables := Set new.
-	realVarNames := Set new.
-	stream 
-	    nextPutAll: 'smalltalk.method({'; lf;
-	    nextPutAll: 'selector: "', aNode selector, '",'; lf.
-	stream nextPutAll: 'source: ', self source asJavascript, ',';lf.
-	stream nextPutAll: 'fn: function('.
-	aNode arguments 
-	    do: [:each | 
-		argVariables add: each.
-		stream nextPutAll: each]
-	    separatedBy: [stream nextPutAll: ', '].
-	stream 
-	    nextPutAll: '){var self=this;', self mylf.
-	str := stream.
-	stream := '' writeStream.
-	self switchTarget: nil.
-	self assert: aNode nodes size = 1.
-	self visit: aNode nodes first.
-	realVarNames ifNotEmpty: [ str nextPutAll: 'var ', (realVarNames asArray join: ','), ';', self mylf ].
-	earlyReturn ifTrue: [
-	    str nextPutAll: 'var $early={}; try{', self mylf].
-	str nextPutAll: stream contents.
-	stream := str.
-	(aNode nodes first nodes notEmpty and: [ |checker|
-	    checker := ReturnNodeChecker new.
-	    checker visit: aNode nodes first nodes last.
-	    checker wasReturnNode]) ifFalse: [ self switchTarget: '^'. self lazyAssignValue: 'self'. self switchTarget: nil ].
-	earlyReturn ifTrue: [
-	    stream nextPutAll: '} catch(e) {if(e===$early) return e[0]; throw e}'].
-	stream nextPutAll: '}'.
-	stream 
-		nextPutAll: ',', String lf, 'messageSends: ';
-		nextPutAll: messageSends asJavascript, ','; lf;
-          	nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
-		nextPutAll: 'referencedClasses: ['.
-	referencedClasses 
-		do: [:each | stream nextPutAll: each printString]
-		separatedBy: [stream nextPutAll: ','].
-	stream nextPutAll: ']'.
-	stream nextPutAll: '})'.
-	self assert: mutables isEmpty
-!
-
-visitReturnNode: aNode
-	self assert: aNode nodes size = 1.
-	nestedBlocks > 0 ifTrue: [
-	    earlyReturn := true].
-	self
-		visit: aNode nodes first
-		targetBeing: (nestedBlocks > 0 ifTrue: ['!!'] ifFalse: ['^']).
-	self lazyAssignValue: ''
-!
-
-visitSendNode: aNode
-        | receiver superSend rcv |
-        (messageSends includes: aNode selector) ifFalse: [
-                messageSends add: aNode selector].
-	
-	self performOptimizations 
-		ifTrue: [
-			(self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifTrue: [ ^self ].
-		].
-
-	rcv := self isolated: aNode receiver.
-        superSend := (lazyVars at: rcv ifAbsent: []) = 'super'.
-        superSend ifTrue: [ mutables remove: rcv. lazyVars at: rcv put: 'self' ].
-
-	self performOptimizations 
-		ifTrue: [ | inline |
-			inline := self inline: aNode selector receiver: rcv argumentNodes: aNode arguments.
-			inline ifNotNil: [ | args |
-				args := inline = true ifTrue: [ aNode arguments ] ifFalse: [ inline ].
-				self prvPutAndClose: [ self send: aNode selector to: rcv arguments: args superSend: superSend ].
-				^self ]].
-	self send: aNode selector to: rcv arguments: aNode arguments superSend: superSend
-!
-
-visitSequenceNode: aNode
-	aNode nodes isEmpty ifFalse: [
-		self sequenceOfNodes: aNode nodes temps: aNode temps ]
-!
-
-visitValueNode: aNode
-	self lazyAssignValue: aNode value asJavascript
-!
-
-visitVariableNode: aNode
-	| varName |
-	(self currentClass allInstanceVariableNames includes: aNode value) 
-		ifTrue: [self lazyAssignExpression: 'self[''@', aNode value, ''']']
-		ifFalse: [
-                  	varName := self safeVariableNameFor: aNode value.
-			(self knownVariables includes: varName) 
-                  		ifFalse: [
-                                  	unknownVariables add: aNode value.
-                                  	aNode assigned 
-                                  		ifTrue: [self lazyAssignExpression: varName]
-                                  		ifFalse: [self lazyAssignExpression: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
-                  		ifTrue: [
-                                  	aNode value = 'thisContext'
-                                  		ifTrue: [self lazyAssignExpression: '(smalltalk.getThisContext())']
-                				ifFalse: [(self pseudoVariables includes: varName)
-							ifTrue: [ self lazyAssignValue: varName ]
-							ifFalse: [ self lazyAssignExpression: varName]]]]
-!
-
-visitVerbatimNode: aNode
-	self lazyAssignValue: aNode value
-! !
-
-ImpCodeGenerator class instanceVariableNames: 'performOptimizations'!
-
-!ImpCodeGenerator class methodsFor: 'accessing'!
-
-performOptimizations
-	^performOptimizations ifNil: [true]
-!
-
-performOptimizations: aBoolean
-	performOptimizations := aBoolean
-! !
-
-NodeVisitor subclass: #ReturnNodeChecker
-	instanceVariableNames: 'wasReturnNode'
-	package: 'Compiler-Visitors'!
-
-!ReturnNodeChecker methodsFor: 'accessing'!
-
-wasReturnNode
-	^wasReturnNode
-! !
-
-!ReturnNodeChecker methodsFor: 'initializing'!
-
-initialize
-	wasReturnNode := false
-! !
-
-!ReturnNodeChecker methodsFor: 'visiting'!
-
-visitReturnNode: aNode
-	wasReturnNode := true
-! !
-

+ 12 - 0
st/Kernel-Classes.st

@@ -216,6 +216,12 @@ subclass: aString instanceVariableNames: aString2 package: aString3
 	    superclass: self subclass: aString asString instanceVariableNames: aString2 package: aString3
 ! !
 
+!Class methodsFor: 'converting'!
+
+asJavascript
+	^ 'smalltalk.', self name
+! !
+
 !Class methodsFor: 'printing'!
 
 printString
@@ -248,6 +254,12 @@ instanceVariableNames: aCollection
 	    class: self instanceVariableNames: aCollection
 ! !
 
+!Metaclass methodsFor: 'converting'!
+
+asJavascript
+	^ 'smalltalk.', self instanceClass name, '.klass'
+! !
+
 !Metaclass methodsFor: 'printing'!
 
 printString

+ 4 - 0
st/Kernel-Objects.st

@@ -1436,6 +1436,10 @@ packages
 	<return self.packages.all()>
 !
 
+pseudoVariableNames
+	^ #('self' 'super' 'nil' 'true' 'false')
+!
+
 removePackage: packageName
 	"Removes a package and all its classes."
 

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott