3 Commits e3d0e88b2b ... 214bc48bf6

Author SHA1 Message Date
  Herby Vojčík 214bc48bf6 Behavior can JS-reparent itself. 4 years ago
  Herby Vojčík 4655803e80 Deprecate #javascriptConstructor(:). 4 years ago
  Herby Vojčík ef4acf0c65 Move parsing and ParseError to Compiler-Core. 4 years ago

+ 12 - 0
lang/API-CHANGES.txt

@@ -1,3 +1,15 @@
+0.24.1:
+
+* Deprecate Behavior >> javascriptConstructor(:)
+
++ Behavior >>
+  + beJavaScriptSubclassOf:
+  + javaScriptConstructor
+  + javaScriptConstructor:
++ ClassBuilder >>
+  + javaScriptSubclassOf:
+
+
 0.23.2:
 
 + Platform class >>

+ 168 - 6
lang/src/Compiler-Core.js

@@ -1,7 +1,12 @@
-define(["amber/boot", "require", "amber/core/Kernel-Collections", "amber/core/Kernel-Objects"], function($boot,requirejs){"use strict";
+define(["amber/boot", "require", "amber/core/Kernel-Collections", "amber/core/Kernel-Exceptions", "amber/core/Kernel-Objects"], function($boot,requirejs){"use strict";
 var $core=$boot.api,nil=$boot.nilAsValue,$nil=$boot.nilAsReceiver,$recv=$boot.asReceiver,$globals=$boot.globals;
 var $pkg = $core.addPackage("Compiler-Core");
 $pkg.innerEval = function (expr) { return eval(expr); };
+$pkg.imports = ["smalltalkParser=amber/parser"];
+//>>excludeStart("imports", pragmas.excludeImports);
+var smalltalkParser;
+$pkg.isReady = new Promise(function (resolve, reject) { requirejs(["amber/parser"], function ($1) {smalltalkParser=$1; resolve();}, reject); });
+//>>excludeEnd("imports");
 $pkg.transport = {"type":"amd","amdNamespace":"amber/core"};
 
 $core.addClass("AbstractCodeGenerator", $globals.Object, ["currentClass", "currentPackage", "source"], "Compiler-Core");
@@ -452,6 +457,29 @@ catch(e) {if(e===$early)return e[0]; throw e}
 }; }),
 $globals.Compiler);
 
+$core.addMethod(
+$core.method({
+selector: "basicParse:",
+protocol: "private",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "basicParse: aString\x0a\x09^ smalltalkParser parse: aString",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["parse:"]
+}, function ($methodClass){ return function (aString){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv(smalltalkParser)._parse_(aString);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"basicParse:",{aString:aString})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Compiler);
+
 $core.addMethod(
 $core.method({
 selector: "cleanCodeGenerator",
@@ -921,19 +949,100 @@ selector: "parse:",
 protocol: "compiling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString"],
-source: "parse: aString\x0a\x09^ Smalltalk parse: aString",
-referencedClasses: ["Smalltalk"],
+source: "parse: aString\x0a\x09| result |\x0a\x09\x0a\x09[ result := self basicParse: aString ] \x0a\x09\x09tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].\x0a\x09\x09\x0a\x09^ result\x0a\x09\x09source: aString;\x0a\x09\x09yourself",
+referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["parse:"]
+messageSends: ["tryCatch:", "basicParse:", "signal", "parseError:parsing:", "source:", "yourself"]
 }, function ($methodClass){ return function (aString){
 var self=this,$self=this;
+var result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $recv($globals.Smalltalk)._parse_(aString);
+var $1;
+$recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString})});
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+result=$self._basicParse_(aString);
+return result;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}))._tryCatch_((function(ex){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv($self._parseError_parsing_(ex,aString))._signal();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)});
+//>>excludeEnd("ctx");
+}));
+$1=result;
+$recv($1)._source_(aString);
+return $recv($1)._yourself();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString,result:result})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Compiler);
+
+$core.addMethod(
+$core.method({
+selector: "parseError:parsing:",
+protocol: "error handling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anException", "aString"],
+source: "parseError: anException parsing: aString\x0a\x09(anException basicAt: 'location')\x0a\x09\x09ifNil: [ ^ anException pass ]\x0a\x09\x09ifNotNil: [ :loc |\x0a\x09\x09\x09^ ParseError new \x0a\x09\x09\x09\x09messageText: \x0a\x09\x09\x09\x09\x09'Parse error on line ', loc start line ,\x0a\x09\x09\x09\x09\x09' column ' , loc start column ,\x0a\x09\x09\x09\x09\x09' : Unexpected character ', (anException basicAt: 'found');\x0a\x09\x09\x09\x09yourself ]",
+referencedClasses: ["ParseError"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["ifNil:ifNotNil:", "basicAt:", "pass", "messageText:", "new", ",", "line", "start", "column", "yourself"]
+}, function ($methodClass){ return function (anException,aString){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1,$2,$9,$8,$7,$6,$5,$4,$3,$receiver;
+$1=$recv(anException)._basicAt_("location");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["basicAt:"]=1;
+//>>excludeEnd("ctx");
+if(($receiver = $1) == null || $receiver.a$nil){
+return $recv(anException)._pass();
+} else {
+var loc;
+loc=$receiver;
+$2=$recv($globals.ParseError)._new();
+$9=$recv(loc)._start();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["start"]=1;
+//>>excludeEnd("ctx");
+$8=$recv($9)._line();
+$7="Parse error on line ".__comma($8);
+$6=$recv($7).__comma(" column ");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=4;
+//>>excludeEnd("ctx");
+$5=$recv($6).__comma($recv($recv(loc)._start())._column());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=3;
+//>>excludeEnd("ctx");
+$4=$recv($5).__comma(" : Unexpected character ");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=2;
+//>>excludeEnd("ctx");
+$3=$recv($4).__comma($recv(anException)._basicAt_("found"));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=1;
+//>>excludeEnd("ctx");
+$recv($2)._messageText_($3);
+return $recv($2)._yourself();
+}
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"parseError:parsing:",{anException:anException,aString:aString})});
 //>>excludeEnd("ctx");
 }; }),
 $globals.Compiler);
@@ -1114,6 +1223,53 @@ return $recv($self._new())._eval_(aString);
 }; }),
 $globals.Compiler.a$cls);
 
+$core.addMethod(
+$core.method({
+selector: "initialize",
+protocol: "initialization",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "initialize\x0a\x09\x22TODO remove, backward compat\x22\x0a\x09Smalltalk globals at: #SmalltalkParser put: smalltalkParser",
+referencedClasses: ["Smalltalk"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["at:put:", "globals"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv($recv($globals.Smalltalk)._globals())._at_put_("SmalltalkParser",smalltalkParser);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"initialize",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Compiler.a$cls);
+
+$core.addMethod(
+$core.method({
+selector: "parse:",
+protocol: "parsing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "parse: aString\x0a\x09^ self new parse: aString",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["parse:", "new"]
+}, function ($methodClass){ return function (aString){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($self._new())._parse_(aString);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Compiler.a$cls);
+
 $core.addMethod(
 $core.method({
 selector: "recompile:",
@@ -1325,6 +1481,12 @@ return $recv($self._new())._evaluate_for_(aString,anObject);
 }; }),
 $globals.Evaluator.a$cls);
 
+
+$core.addClass("ParseError", $globals.Error, [], "Compiler-Core");
+//>>excludeStart("ide", pragmas.excludeIdeData);
+$globals.ParseError.comment="Instance of ParseError are signaled on any parsing error.\x0aSee `Compiler >> #parse:`";
+//>>excludeEnd("ide");
+
 $core.addMethod(
 $core.method({
 selector: "asVariableName",

+ 49 - 1
lang/src/Compiler-Core.st

@@ -1,4 +1,5 @@
 Smalltalk createPackage: 'Compiler-Core'!
+(Smalltalk packageAt: 'Compiler-Core' ifAbsent: [ self error: 'Package not created: Compiler-Core' ]) imports: {'smalltalkParser' -> 'amber/parser'}!
 Object subclass: #AbstractCodeGenerator
 	slots: {#currentClass. #currentPackage. #source}
 	package: 'Compiler-Core'!
@@ -240,7 +241,14 @@ install: aString forClass: aBehavior protocol: anotherString
 !
 
 parse: aString
-	^ Smalltalk parse: aString
+	| result |
+	
+	[ result := self basicParse: aString ] 
+		tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].
+		
+	^ result
+		source: aString;
+		yourself
 !
 
 parseExpression: aString
@@ -264,6 +272,26 @@ recompileAll
 		displayingProgress: 'Compiling all classes...'
 ! !
 
+!Compiler methodsFor: 'error handling'!
+
+parseError: anException parsing: aString
+	(anException basicAt: 'location')
+		ifNil: [ ^ anException pass ]
+		ifNotNil: [ :loc |
+			^ ParseError new 
+				messageText: 
+					'Parse error on line ', loc start line ,
+					' column ' , loc start column ,
+					' : Unexpected character ', (anException basicAt: 'found');
+				yourself ]
+! !
+
+!Compiler methodsFor: 'private'!
+
+basicParse: aString
+	^ smalltalkParser parse: aString
+! !
+
 !Compiler class methodsFor: 'compiling'!
 
 recompile: aClass
@@ -281,6 +309,19 @@ eval: aString
 	^ self new eval: aString
 ! !
 
+!Compiler class methodsFor: 'initialization'!
+
+initialize
+	"TODO remove, backward compat"
+	Smalltalk globals at: #SmalltalkParser put: smalltalkParser
+! !
+
+!Compiler class methodsFor: 'parsing'!
+
+parse: aString
+	^ self new parse: aString
+! !
+
 Object subclass: #DoIt
 	slots: {}
 	package: 'Compiler-Core'!
@@ -335,6 +376,13 @@ evaluate: aString for: anObject
 	^ self new evaluate: aString for: anObject
 ! !
 
+Error subclass: #ParseError
+	slots: {}
+	package: 'Compiler-Core'!
+!ParseError commentStamp!
+Instance of ParseError are signaled on any parsing error.
+See `Compiler >> #parse:`!
+
 !String methodsFor: '*Compiler-Core'!
 
 asVariableName

+ 109 - 10
lang/src/Kernel-Classes.js

@@ -246,6 +246,30 @@ return self;
 }; }),
 $globals.Behavior);
 
+$core.addMethod(
+$core.method({
+selector: "beJavaScriptSubclassOf:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aJavaScriptFunction"],
+source: "beJavaScriptSubclassOf: aJavaScriptFunction\x0a\x09\x22Set the JS constructor to subclass of aJavaScriptFunction.\x0a\x09That way I stay part of (simulated) Smalltalk hierarchy,\x0a\x09but my instances will physically be instanceof aJavaScriptFunction.\x22\x0a\x09\x0a\x09self javaScriptConstructor:\x0a\x09\x09(ClassBuilder new javaScriptSubclassOf: aJavaScriptFunction)",
+referencedClasses: ["ClassBuilder"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["javaScriptConstructor:", "javaScriptSubclassOf:", "new"]
+}, function ($methodClass){ return function (aJavaScriptFunction){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._javaScriptConstructor_($recv($recv($globals.ClassBuilder)._new())._javaScriptSubclassOf_(aJavaScriptFunction));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"beJavaScriptSubclassOf:",{aJavaScriptFunction:aJavaScriptFunction})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Behavior);
+
 $core.addMethod(
 $core.method({
 selector: "canUnderstand:",
@@ -406,11 +430,11 @@ $globals.Behavior);
 
 $core.addMethod(
 $core.method({
-selector: "javascriptConstructor",
+selector: "javaScriptConstructor",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "javascriptConstructor\x0a\x09\x22Answer the JS constructor used to instantiate. See kernel-language.js\x22\x0a\x09\x0a\x09^ fn",
+source: "javaScriptConstructor\x0a\x09\x22Answer the JS constructor used to instantiate. See kernel-language.js\x22\x0a\x09\x0a\x09^ fn",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
@@ -424,11 +448,11 @@ $globals.Behavior);
 
 $core.addMethod(
 $core.method({
-selector: "javascriptConstructor:",
+selector: "javaScriptConstructor:",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aJavaScriptFunction"],
-source: "javascriptConstructor: aJavaScriptFunction\x0a\x09\x22Set the JS constructor used to instantiate.\x0a\x09See the JS counter-part in boot.js `$core.setClassConstructor'\x22\x0a\x09\x0a\x09Smalltalk core setClassConstructor: self to: aJavaScriptFunction",
+source: "javaScriptConstructor: aJavaScriptFunction\x0a\x09\x22Set the JS constructor used to instantiate.\x0a\x09See the JS counter-part in boot.js `$core.setClassConstructor'\x22\x0a\x09\x0a\x09Smalltalk core setClassConstructor: self to: aJavaScriptFunction",
 referencedClasses: ["Smalltalk"],
 //>>excludeEnd("ide");
 pragmas: [],
@@ -441,6 +465,54 @@ return $core.withContext(function($ctx1) {
 $recv($recv($globals.Smalltalk)._core())._setClassConstructor_to_(self,aJavaScriptFunction);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"javaScriptConstructor:",{aJavaScriptFunction:aJavaScriptFunction})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Behavior);
+
+$core.addMethod(
+$core.method({
+selector: "javascriptConstructor",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "javascriptConstructor\x0a\x09self deprecatedAPI: 'Use #javaScriptConstructor instead.'.\x0a\x09^ self javaScriptConstructor",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["deprecatedAPI:", "javaScriptConstructor"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._deprecatedAPI_("Use #javaScriptConstructor instead.");
+return $self._javaScriptConstructor();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"javascriptConstructor",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Behavior);
+
+$core.addMethod(
+$core.method({
+selector: "javascriptConstructor:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aJavaScriptFunction"],
+source: "javascriptConstructor: aJavaScriptFunction\x0a\x09self deprecatedAPI: 'Use #javaScriptConstructor: instead.'.\x0a\x09^ self javaScriptConstructor: aJavaScriptFunction",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["deprecatedAPI:", "javaScriptConstructor:"]
+}, function ($methodClass){ return function (aJavaScriptFunction){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._deprecatedAPI_("Use #javaScriptConstructor: instead.");
+return $self._javaScriptConstructor_(aJavaScriptFunction);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"javascriptConstructor:",{aJavaScriptFunction:aJavaScriptFunction})});
 //>>excludeEnd("ctx");
 }; }),
@@ -527,17 +599,17 @@ selector: "prototype",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "prototype\x0a\x09^ self javascriptConstructor prototype",
+source: "prototype\x0a\x09^ self javaScriptConstructor prototype",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["prototype", "javascriptConstructor"]
+messageSends: ["prototype", "javaScriptConstructor"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $recv($self._javascriptConstructor())._prototype();
+return $recv($self._javaScriptConstructor())._prototype();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"prototype",{})});
 //>>excludeEnd("ctx");
@@ -849,17 +921,17 @@ selector: "provided",
 protocol: "converting",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "provided\x0a\x09\x22Returns JS proxy that allows to access 'static API', as in\x0a\x09  Number provided EPSILON\x0a\x09that forwards to (wrapped JS) constructor function.\x22\x0a\x09\x0a\x09^ self javascriptConstructor provided",
+source: "provided\x0a\x09\x22Returns JS proxy that allows to access 'static API', as in\x0a\x09  Number provided EPSILON\x0a\x09that forwards to (wrapped JS) constructor function.\x22\x0a\x09\x0a\x09^ self javaScriptConstructor provided",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["provided", "javascriptConstructor"]
+messageSends: ["provided", "javaScriptConstructor"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $recv($self._javascriptConstructor())._provided();
+return $recv($self._javaScriptConstructor())._provided();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"provided",{})});
 //>>excludeEnd("ctx");
@@ -1686,6 +1758,33 @@ return self;
 }; }),
 $globals.ClassBuilder);
 
+$core.addMethod(
+$core.method({
+selector: "javaScriptSubclassOf:",
+protocol: "class definition",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["javaScriptClass"],
+source: "javaScriptSubclassOf: javaScriptClass\x0a\x09<inlineJS: '\x0a\x09\x09var subclass = function () {};\x0a\x09\x09subclass.prototype = Object.create(javaScriptClass.prototype);\x0a\x09\x09return subclass;'>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [["inlineJS:", ["\x0a\x09\x09var subclass = function () {};\x0a\x09\x09subclass.prototype = Object.create(javaScriptClass.prototype);\x0a\x09\x09return subclass;"]]],
+messageSends: []
+}, function ($methodClass){ return function (javaScriptClass){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+
+		var subclass = function () {};
+		subclass.prototype = Object.create(javaScriptClass.prototype);
+		return subclass;;
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"javaScriptSubclassOf:",{javaScriptClass:javaScriptClass})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.ClassBuilder);
+
 $core.addMethod(
 $core.method({
 selector: "migrateClass:superclass:",

+ 30 - 4
lang/src/Kernel-Classes.st

@@ -52,23 +52,42 @@ basicOrganization: aClassOrganizer
 	organization := aClassOrganizer
 !
 
+beJavaScriptSubclassOf: aJavaScriptFunction
+	"Set the JS constructor to subclass of aJavaScriptFunction.
+	That way I stay part of (simulated) Smalltalk hierarchy,
+	but my instances will physically be instanceof aJavaScriptFunction."
+	
+	self javaScriptConstructor:
+		(ClassBuilder new javaScriptSubclassOf: aJavaScriptFunction)
+!
+
 instanceVariableNames
 	^ slots
 !
 
-javascriptConstructor
+javaScriptConstructor
 	"Answer the JS constructor used to instantiate. See kernel-language.js"
 	
 	^ fn
 !
 
-javascriptConstructor: aJavaScriptFunction
+javaScriptConstructor: aJavaScriptFunction
 	"Set the JS constructor used to instantiate.
 	See the JS counter-part in boot.js `$core.setClassConstructor'"
 	
 	Smalltalk core setClassConstructor: self to: aJavaScriptFunction
 !
 
+javascriptConstructor
+	self deprecatedAPI: 'Use #javaScriptConstructor instead.'.
+	^ self javaScriptConstructor
+!
+
+javascriptConstructor: aJavaScriptFunction
+	self deprecatedAPI: 'Use #javaScriptConstructor: instead.'.
+	^ self javaScriptConstructor: aJavaScriptFunction
+!
+
 lookupSelector: selector
 	"Look up the given selector in my methodDictionary.
 	Return the corresponding method if found.
@@ -86,7 +105,7 @@ lookupSelector: selector
 !
 
 prototype
-	^ self javascriptConstructor prototype
+	^ self javaScriptConstructor prototype
 !
 
 subclasses
@@ -206,7 +225,7 @@ provided
 	  Number provided EPSILON
 	that forwards to (wrapped JS) constructor function."
 	
-	^ self javascriptConstructor provided
+	^ self javaScriptConstructor provided
 ! !
 
 !Class methodsFor: 'enumerating'!
@@ -355,6 +374,13 @@ class: aClass slots: aCollection
 			yourself)
 !
 
+javaScriptSubclassOf: javaScriptClass
+	<inlineJS: '
+		var subclass = function () {};
+		subclass.prototype = Object.create(javaScriptClass.prototype);
+		return subclass;'>
+!
+
 superclass: aClass subclass: className
 	^ self superclass: aClass subclass: className slots: #() package: nil
 !

+ 9 - 132
lang/src/Kernel-Infrastructure.js

@@ -1,12 +1,7 @@
-define(["amber/boot", "require", "amber/core/Kernel-Collections", "amber/core/Kernel-Exceptions", "amber/core/Kernel-Objects", "amber/core/Kernel-Promises"], function($boot,requirejs){"use strict";
+define(["amber/boot", "require", "amber/core/Kernel-Collections", "amber/core/Kernel-Objects", "amber/core/Kernel-Promises"], function($boot,requirejs){"use strict";
 var $core=$boot.api,nil=$boot.nilAsValue,$nil=$boot.nilAsReceiver,$recv=$boot.asReceiver,$globals=$boot.globals;
 var $pkg = $core.addPackage("Kernel-Infrastructure");
 $pkg.innerEval = function (expr) { return eval(expr); };
-$pkg.imports = ["smalltalkParser=amber/parser"];
-//>>excludeStart("imports", pragmas.excludeImports);
-var smalltalkParser;
-$pkg.isReady = new Promise(function (resolve, reject) { requirejs(["amber/parser"], function ($1) {smalltalkParser=$1; resolve();}, reject); });
-//>>excludeEnd("imports");
 $pkg.transport = {"type":"amd","amdNamespace":"amber/core"};
 
 $core.addClass("AmberBootstrapInitialization", $globals.Object, [], "Kernel-Infrastructure");
@@ -92,11 +87,11 @@ selector: "run",
 protocol: "public api",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "run\x0a\x09SmalltalkImage initialize.\x0a\x09self\x0a\x09\x09organizeClasses;\x0a\x09\x09organizeMethods.\x0a\x09^ Smalltalk postLoad\x0a\x09\x09\x22TODO remove, backward compat\x22\x0a\x09\x09then: [ Smalltalk globals at: #SmalltalkParser put: smalltalkParser ]",
+source: "run\x0a\x09SmalltalkImage initialize.\x0a\x09self\x0a\x09\x09organizeClasses;\x0a\x09\x09organizeMethods.\x0a\x09^ Smalltalk postLoad",
 referencedClasses: ["SmalltalkImage", "Smalltalk"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["initialize", "organizeClasses", "organizeMethods", "then:", "postLoad", "at:put:", "globals"]
+messageSends: ["initialize", "organizeClasses", "organizeMethods", "postLoad"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -105,15 +100,7 @@ return $core.withContext(function($ctx1) {
 $recv($globals.SmalltalkImage)._initialize();
 $self._organizeClasses();
 $self._organizeMethods();
-return $recv($recv($globals.Smalltalk)._postLoad())._then_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($recv($globals.Smalltalk)._globals())._at_put_("SmalltalkParser",smalltalkParser);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
+return $recv($globals.Smalltalk)._postLoad();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"run",{})});
 //>>excludeEnd("ctx");
@@ -2708,12 +2695,6 @@ return self;
 $globals.PackageStateObserver.a$cls);
 
 
-$core.addClass("ParseError", $globals.Error, [], "Kernel-Infrastructure");
-//>>excludeStart("ide", pragmas.excludeIdeData);
-$globals.ParseError.comment="Instance of ParseError are signaled on any parsing error.\x0aSee `Smalltalk >> #parse:`";
-//>>excludeEnd("ide");
-
-
 $core.addClass("Setting", $globals.Object, ["key", "value", "defaultValue"], "Kernel-Infrastructure");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.Setting.comment="I represent a setting **stored** at `Smalltalk settings`. \x0aIn the current implementation, `Smalltalk settings` is an object persisted in the localStorage.\x0a\x0a## API\x0a\x0aA `Setting` value can be read using `value` and set using `value:`.\x0a\x0aSettings are accessed with `'key' asSetting` or `'key' asSettingIfAbsent: aDefaultValue`.\x0a\x0aTo read the value of a setting you can also use the convenience:\x0a\x0a`theValueSet :=  'any.characteristic' settingValue` \x0a\x0aor with a default using:\x0a\x0a `theEnsuredValueSet := 'any.characteristic' settingValueIfAbsent: true`";
@@ -3048,29 +3029,6 @@ return $recv($globals.Package)._new_(packageName);
 }; }),
 $globals.SmalltalkImage);
 
-$core.addMethod(
-$core.method({
-selector: "basicParse:",
-protocol: "private",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aString"],
-source: "basicParse: aString\x0a\x09^ smalltalkParser parse: aString",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["parse:"]
-}, function ($methodClass){ return function (aString){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-return $recv(smalltalkParser)._parse_(aString);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"basicParse:",{aString:aString})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.SmalltalkImage);
-
 $core.addMethod(
 $core.method({
 selector: "beClean",
@@ -3524,100 +3482,19 @@ selector: "parse:",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString"],
-source: "parse: aString\x0a\x09| result |\x0a\x09\x0a\x09[ result := self basicParse: aString ] \x0a\x09\x09tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].\x0a\x09\x09\x0a\x09^ result\x0a\x09\x09source: aString;\x0a\x09\x09yourself",
-referencedClasses: [],
+source: "parse: aString\x0a\x09^ Compiler new parse: aString",
+referencedClasses: ["Compiler"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["tryCatch:", "basicParse:", "signal", "parseError:parsing:", "source:", "yourself"]
+messageSends: ["parse:", "new"]
 }, function ($methodClass){ return function (aString){
 var self=this,$self=this;
-var result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$recv((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-result=$self._basicParse_(aString);
-return result;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}))._tryCatch_((function(ex){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($self._parseError_parsing_(ex,aString))._signal();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
-$1=result;
-$recv($1)._source_(aString);
-return $recv($1)._yourself();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString,result:result})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.SmalltalkImage);
-
-$core.addMethod(
-$core.method({
-selector: "parseError:parsing:",
-protocol: "error handling",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anException", "aString"],
-source: "parseError: anException parsing: aString\x0a\x09(anException basicAt: 'location')\x0a\x09\x09ifNil: [ ^ anException pass ]\x0a\x09\x09ifNotNil: [ :loc |\x0a\x09\x09\x09^ ParseError new \x0a\x09\x09\x09\x09messageText: \x0a\x09\x09\x09\x09\x09'Parse error on line ', loc start line ,\x0a\x09\x09\x09\x09\x09' column ' , loc start column ,\x0a\x09\x09\x09\x09\x09' : Unexpected character ', (anException basicAt: 'found');\x0a\x09\x09\x09\x09yourself ]",
-referencedClasses: ["ParseError"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["ifNil:ifNotNil:", "basicAt:", "pass", "messageText:", "new", ",", "line", "start", "column", "yourself"]
-}, function ($methodClass){ return function (anException,aString){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1,$2,$9,$8,$7,$6,$5,$4,$3,$receiver;
-$1=$recv(anException)._basicAt_("location");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["basicAt:"]=1;
-//>>excludeEnd("ctx");
-if(($receiver = $1) == null || $receiver.a$nil){
-return $recv(anException)._pass();
-} else {
-var loc;
-loc=$receiver;
-$2=$recv($globals.ParseError)._new();
-$9=$recv(loc)._start();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["start"]=1;
-//>>excludeEnd("ctx");
-$8=$recv($9)._line();
-$7="Parse error on line ".__comma($8);
-$6=$recv($7).__comma(" column ");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=4;
-//>>excludeEnd("ctx");
-$5=$recv($6).__comma($recv($recv(loc)._start())._column());
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=3;
-//>>excludeEnd("ctx");
-$4=$recv($5).__comma(" : Unexpected character ");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=2;
-//>>excludeEnd("ctx");
-$3=$recv($4).__comma($recv(anException)._basicAt_("found"));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx[","]=1;
-//>>excludeEnd("ctx");
-$recv($2)._messageText_($3);
-return $recv($2)._yourself();
-}
-return self;
+return $recv($recv($globals.Compiler)._new())._parse_(aString);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"parseError:parsing:",{anException:anException,aString:aString})});
+}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString})});
 //>>excludeEnd("ctx");
 }; }),
 $globals.SmalltalkImage);

+ 1 - 34
lang/src/Kernel-Infrastructure.st

@@ -1,5 +1,4 @@
 Smalltalk createPackage: 'Kernel-Infrastructure'!
-(Smalltalk packageAt: 'Kernel-Infrastructure' ifAbsent: [ self error: 'Package not created: Kernel-Infrastructure' ]) imports: {'smalltalkParser' -> 'amber/parser'}!
 Object subclass: #AmberBootstrapInitialization
 	slots: {}
 	package: 'Kernel-Infrastructure'!
@@ -24,8 +23,6 @@ run
 		organizeClasses;
 		organizeMethods.
 	^ Smalltalk postLoad
-		"TODO remove, backward compat"
-		then: [ Smalltalk globals at: #SmalltalkParser put: smalltalkParser ]
 ! !
 
 ProtoObject subclass: #JSObjectProxy
@@ -714,13 +711,6 @@ initialize
 	self current observeSystem
 ! !
 
-Error subclass: #ParseError
-	slots: {}
-	package: 'Kernel-Infrastructure'!
-!ParseError commentStamp!
-Instance of ParseError are signaled on any parsing error.
-See `Smalltalk >> #parse:`!
-
 Object subclass: #Setting
 	slots: {#key. #value. #defaultValue}
 	package: 'Kernel-Infrastructure'!
@@ -841,14 +831,7 @@ optOut: anObject
 !
 
 parse: aString
-	| result |
-	
-	[ result := self basicParse: aString ] 
-		tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].
-		
-	^ result
-		source: aString;
-		yourself
+	^ Compiler new parse: aString
 !
 
 pseudoVariableNames
@@ -931,18 +914,6 @@ asSmalltalkException: anObject
 	^ ((self isSmalltalkObject: anObject) and: [ anObject isKindOf: Error ])
 		ifTrue: [ anObject ]
 		ifFalse: [ JavaScriptException on: anObject ]
-!
-
-parseError: anException parsing: aString
-	(anException basicAt: 'location')
-		ifNil: [ ^ anException pass ]
-		ifNotNil: [ :loc |
-			^ ParseError new 
-				messageText: 
-					'Parse error on line ', loc start line ,
-					' column ' , loc start column ,
-					' : Unexpected character ', (anException basicAt: 'found');
-				yourself ]
 ! !
 
 !SmalltalkImage methodsFor: 'globals'!
@@ -1046,10 +1017,6 @@ basicCreatePackage: packageName
 	^ self packageDictionary at: packageName ifAbsentPut: [ Package new: packageName ]
 !
 
-basicParse: aString
-	^ smalltalkParser parse: aString
-!
-
 deleteClass: aClass
 	"Deletes a class by deleting its binding only. Use #removeClass instead"
 	

+ 6 - 6
lang/src/Kernel-Tests.js

@@ -2543,11 +2543,11 @@ selector: "testSetJavaScriptConstructor",
 protocol: "tests",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testSetJavaScriptConstructor\x0a\x09| instance |\x0a\x09theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.\x0a\x09theClass javascriptConstructor: self jsConstructor.\x0a\x09\x22part took from copy class test\x22\x0a\x09self assert: theClass superclass == ObjectMock superclass.\x0a\x09self assert: theClass instanceVariableNames == ObjectMock instanceVariableNames.\x0a\x09self assert: theClass name equals: 'ObjectMock2'.\x0a\x09self assert: theClass package == ObjectMock package.\x0a\x09self assert: theClass methodDictionary keys equals: ObjectMock methodDictionary keys.\x0a\x09\x22testing specific to late-coupled detached root class\x22\x0a\x09instance := theClass new.\x0a\x09self assert: instance class == theClass.\x0a\x09self assert: instance value equals: 4.\x0a\x09self shouldnt: [ instance foo: 9 ] raise: Error.\x0a\x09self assert: instance foo equals: 9",
+source: "testSetJavaScriptConstructor\x0a\x09| instance |\x0a\x09theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.\x0a\x09theClass javaScriptConstructor: self jsConstructor.\x0a\x09\x22part took from copy class test\x22\x0a\x09self assert: theClass superclass == ObjectMock superclass.\x0a\x09self assert: theClass instanceVariableNames == ObjectMock instanceVariableNames.\x0a\x09self assert: theClass name equals: 'ObjectMock2'.\x0a\x09self assert: theClass package == ObjectMock package.\x0a\x09self assert: theClass methodDictionary keys equals: ObjectMock methodDictionary keys.\x0a\x09\x22testing specific to late-coupled detached root class\x22\x0a\x09instance := theClass new.\x0a\x09self assert: instance class == theClass.\x0a\x09self assert: instance value equals: 4.\x0a\x09self shouldnt: [ instance foo: 9 ] raise: Error.\x0a\x09self assert: instance foo equals: 9",
 referencedClasses: ["ObjectMock", "Error"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["copyClass:named:", "javascriptConstructor:", "jsConstructor", "assert:", "==", "superclass", "instanceVariableNames", "assert:equals:", "name", "package", "keys", "methodDictionary", "new", "class", "value", "shouldnt:raise:", "foo:", "foo"]
+messageSends: ["copyClass:named:", "javaScriptConstructor:", "jsConstructor", "assert:", "==", "superclass", "instanceVariableNames", "assert:equals:", "name", "package", "keys", "methodDictionary", "new", "class", "value", "shouldnt:raise:", "foo:", "foo"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 var instance;
@@ -2556,7 +2556,7 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 var $2,$1,$4,$3,$6,$5,$8,$7;
 $self.theClass=$recv($self.builder)._copyClass_named_($globals.ObjectMock,"ObjectMock2");
-$recv($self.theClass)._javascriptConstructor_($self._jsConstructor());
+$recv($self.theClass)._javaScriptConstructor_($self._jsConstructor());
 $2=$recv($self.theClass)._superclass();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["superclass"]=1;
@@ -2662,11 +2662,11 @@ selector: "testTrickySetJavaScriptConstructor",
 protocol: "tests",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testTrickySetJavaScriptConstructor\x0a\x09| instance |\x0a\x09theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.\x0a\x09theClass javascriptConstructor: self trickyJsConstructor.\x0a\x09\x22part took from copy class test\x22\x0a\x09self assert: theClass superclass == ObjectMock superclass.\x0a\x09self assert: theClass instanceVariableNames == ObjectMock instanceVariableNames.\x0a\x09self assert: theClass name equals: 'ObjectMock2'.\x0a\x09self assert: theClass package == ObjectMock package.\x0a\x09self assert: theClass methodDictionary keys equals: ObjectMock methodDictionary keys.\x0a\x09\x22testing specific to late-coupled detached root class\x22\x0a\x09instance := theClass new.\x0a\x09self assert: instance class == theClass.\x0a\x09self assert: instance value equals: 4.\x0a\x09self shouldnt: [ instance foo: 9 ] raise: Error.\x0a\x09self assert: instance foo equals: 9",
+source: "testTrickySetJavaScriptConstructor\x0a\x09| instance |\x0a\x09theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.\x0a\x09theClass javaScriptConstructor: self trickyJsConstructor.\x0a\x09\x22part took from copy class test\x22\x0a\x09self assert: theClass superclass == ObjectMock superclass.\x0a\x09self assert: theClass instanceVariableNames == ObjectMock instanceVariableNames.\x0a\x09self assert: theClass name equals: 'ObjectMock2'.\x0a\x09self assert: theClass package == ObjectMock package.\x0a\x09self assert: theClass methodDictionary keys equals: ObjectMock methodDictionary keys.\x0a\x09\x22testing specific to late-coupled detached root class\x22\x0a\x09instance := theClass new.\x0a\x09self assert: instance class == theClass.\x0a\x09self assert: instance value equals: 4.\x0a\x09self shouldnt: [ instance foo: 9 ] raise: Error.\x0a\x09self assert: instance foo equals: 9",
 referencedClasses: ["ObjectMock", "Error"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["copyClass:named:", "javascriptConstructor:", "trickyJsConstructor", "assert:", "==", "superclass", "instanceVariableNames", "assert:equals:", "name", "package", "keys", "methodDictionary", "new", "class", "value", "shouldnt:raise:", "foo:", "foo"]
+messageSends: ["copyClass:named:", "javaScriptConstructor:", "trickyJsConstructor", "assert:", "==", "superclass", "instanceVariableNames", "assert:equals:", "name", "package", "keys", "methodDictionary", "new", "class", "value", "shouldnt:raise:", "foo:", "foo"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 var instance;
@@ -2675,7 +2675,7 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 var $2,$1,$4,$3,$6,$5,$8,$7;
 $self.theClass=$recv($self.builder)._copyClass_named_($globals.ObjectMock,"ObjectMock2");
-$recv($self.theClass)._javascriptConstructor_($self._trickyJsConstructor());
+$recv($self.theClass)._javaScriptConstructor_($self._trickyJsConstructor());
 $2=$recv($self.theClass)._superclass();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["superclass"]=1;

+ 2 - 2
lang/src/Kernel-Tests.st

@@ -508,7 +508,7 @@ testMetaclassSubclasses
 testSetJavaScriptConstructor
 	| instance |
 	theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.
-	theClass javascriptConstructor: self jsConstructor.
+	theClass javaScriptConstructor: self jsConstructor.
 	"part took from copy class test"
 	self assert: theClass superclass == ObjectMock superclass.
 	self assert: theClass instanceVariableNames == ObjectMock instanceVariableNames.
@@ -530,7 +530,7 @@ testSlotsFromInstanceVariablesString
 testTrickySetJavaScriptConstructor
 	| instance |
 	theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.
-	theClass javascriptConstructor: self trickyJsConstructor.
+	theClass javaScriptConstructor: self trickyJsConstructor.
 	"part took from copy class test"
 	self assert: theClass superclass == ObjectMock superclass.
 	self assert: theClass instanceVariableNames == ObjectMock instanceVariableNames.