ソースを参照

Fixed #654 for Interpreter.

Matthias Springer 10 年 前
コミット
780b0f6881

+ 32 - 33
js/Compiler-Interpreter.deploy.js

@@ -2226,10 +2226,14 @@ selector: "visitClassReferenceNode:",
 fn: function (aNode){
 var self=this;
 function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
+function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
 return smalltalk.withContext(function($ctx1) { 
-self._push_(_st(_st($Smalltalk())._current())._at_(_st(aNode)._value()));
+self._push_(_st(_st($Smalltalk())._current())._at_ifAbsent_(_st(aNode)._value(),(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st($PlatformInterface())._globals())._at_(_st(aNode)._value());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})})));
 return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.Interpreter)})},
-messageSends: ["push:", "at:", "current", "value"]}),
+messageSends: ["push:", "at:ifAbsent:", "current", "value", "at:", "globals"]}),
 smalltalk.Interpreter);
 
 smalltalk.addMethod(
@@ -2344,42 +2348,37 @@ smalltalk.method({
 selector: "visitVariableNode:",
 fn: function (aNode){
 var self=this;
+function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$5,$4;
+var $1,$3,$2,$4,$6,$7,$8,$5;
+var $early={};
+try {
 $1=_st(_st(aNode)._binding())._isUnknownVar();
-if(smalltalk.assert($1)){
-$2=self._push_(_st(window)._at_ifAbsent_(_st(aNode)._value(),(function(){
+$2=(function(){
 return smalltalk.withContext(function($ctx2) {
+$3=self._push_(_st(_st($PlatformInterface())._globals())._at_ifAbsent_(_st(aNode)._value(),(function(){
+return smalltalk.withContext(function($ctx3) {
 return self._error_("Unknown variable");
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})})));
-return $2;
-};
-$3=self;
-$5=_st(_st(aNode)._binding())._isInstanceVar();
-if(smalltalk.assert($5)){
-$4=_st(_st(self._context())._receiver())._instVarAt_(_st(aNode)._value());
-} else {
-$4=_st(self._context())._localAt_(_st(aNode)._value());
-};
-_st($3)._push_($4);
-return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.Interpreter)})},
-messageSends: ["ifTrue:", "isUnknownVar", "binding", "push:", "at:ifAbsent:", "value", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:"]}),
-smalltalk.Interpreter);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "xxxDoIt",
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st((function(){
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})})));
+throw $early=[$3];
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})});
+_st($1)._ifTrue_($2);
+$4=self;
+$6=_st(_st(aNode)._binding())._isInstanceVar();
+$7=(function(){
 return smalltalk.withContext(function($ctx2) {
-return self._step();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._value();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"xxxDoIt",{},smalltalk.Interpreter)})},
-messageSends: ["value", "step"]}),
+return _st(_st(self._context())._receiver())._instVarAt_(_st(aNode)._value());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})});
+$8=(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._context())._localAt_(_st(aNode)._value());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})});
+$5=_st($6)._ifTrue_ifFalse_($7,$8);
+_st($4)._push_($5);
+return self}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.Interpreter)})},
+messageSends: ["ifTrue:", "isUnknownVar", "binding", "push:", "at:ifAbsent:", "globals", "value", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:"]}),
 smalltalk.Interpreter);
 
 

+ 37 - 43
js/Compiler-Interpreter.js

@@ -2929,13 +2929,17 @@ category: 'visiting',
 fn: function (aNode){
 var self=this;
 function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
+function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
 return smalltalk.withContext(function($ctx1) { 
-self._push_(_st(_st($Smalltalk())._current())._at_(_st(aNode)._value()));
+self._push_(_st(_st($Smalltalk())._current())._at_ifAbsent_(_st(aNode)._value(),(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st($PlatformInterface())._globals())._at_(_st(aNode)._value());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})})));
 return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.Interpreter)})},
 args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09self push: (Smalltalk current at: aNode value)",
-messageSends: ["push:", "at:", "current", "value"],
-referencedClasses: ["Smalltalk"]
+source: "visitClassReferenceNode: aNode\x0a\x09self push: (Smalltalk current \x0a\x09\x09at: aNode value \x0a\x09\x09ifAbsent: [ PlatformInterface globals at: aNode value ])",
+messageSends: ["push:", "at:ifAbsent:", "current", "value", "at:", "globals"],
+referencedClasses: ["Smalltalk", "PlatformInterface"]
 }),
 smalltalk.Interpreter);
 
@@ -3087,50 +3091,40 @@ selector: "visitVariableNode:",
 category: 'visiting',
 fn: function (aNode){
 var self=this;
+function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$5,$4;
+var $1,$3,$2,$4,$6,$7,$8,$5;
+var $early={};
+try {
 $1=_st(_st(aNode)._binding())._isUnknownVar();
-if(smalltalk.assert($1)){
-$2=self._push_(_st(window)._at_ifAbsent_(_st(aNode)._value(),(function(){
+$2=(function(){
 return smalltalk.withContext(function($ctx2) {
+$3=self._push_(_st(_st($PlatformInterface())._globals())._at_ifAbsent_(_st(aNode)._value(),(function(){
+return smalltalk.withContext(function($ctx3) {
 return self._error_("Unknown variable");
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})})));
-return $2;
-};
-$3=self;
-$5=_st(_st(aNode)._binding())._isInstanceVar();
-if(smalltalk.assert($5)){
-$4=_st(_st(self._context())._receiver())._instVarAt_(_st(aNode)._value());
-} else {
-$4=_st(self._context())._localAt_(_st(aNode)._value());
-};
-_st($3)._push_($4);
-return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.Interpreter)})},
-args: ["aNode"],
-source: "visitVariableNode: aNode\x0a\x09aNode binding isUnknownVar ifTrue: [\x0a\x09\x09^ self push: (window at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].\x0a\x09\x09\x0a\x09self push: (aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode value ]\x0a\x09\x09ifFalse: [ self context localAt: aNode value ])",
-messageSends: ["ifTrue:", "isUnknownVar", "binding", "push:", "at:ifAbsent:", "value", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:"],
-referencedClasses: []
-}),
-smalltalk.Interpreter);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "xxxDoIt",
-category: 'xxxDoIt',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st((function(){
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})})));
+throw $early=[$3];
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})});
+_st($1)._ifTrue_($2);
+$4=self;
+$6=_st(_st(aNode)._binding())._isInstanceVar();
+$7=(function(){
 return smalltalk.withContext(function($ctx2) {
-return self._step();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._value();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"xxxDoIt",{},smalltalk.Interpreter)})},
-args: [],
-source: "xxxDoIt ^[self step] value",
-messageSends: ["value", "step"],
-referencedClasses: []
+return _st(_st(self._context())._receiver())._instVarAt_(_st(aNode)._value());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})});
+$8=(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._context())._localAt_(_st(aNode)._value());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})});
+$5=_st($6)._ifTrue_ifFalse_($7,$8);
+_st($4)._push_($5);
+return self}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.Interpreter)})},
+args: ["aNode"],
+source: "visitVariableNode: aNode\x0a\x09aNode binding isUnknownVar ifTrue: [\x0a\x09\x09^ self push: (PlatformInterface globals at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].\x0a\x09\x09\x0a\x09self push: (aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode value ]\x0a\x09\x09ifFalse: [ self context localAt: aNode value ])",
+messageSends: ["ifTrue:", "isUnknownVar", "binding", "push:", "at:ifAbsent:", "globals", "value", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:"],
+referencedClasses: ["PlatformInterface"]
 }),
 smalltalk.Interpreter);
 

+ 4 - 1
js/Compiler-Tests.deploy.js

@@ -613,8 +613,11 @@ smalltalk.method({
 selector: "testGlobalVar",
 fn: function (){
 var self=this;
+function $BlockClosure(){return smalltalk.BlockClosure||(typeof BlockClosure=="undefined"?nil:BlockClosure)}
 return smalltalk.withContext(function($ctx1) { 
-self._assert_equals_(self._interpret_("foo ^ console"),console);
+self._assert_equals_(self._interpret_("foo ^ eval class"),$BlockClosure());
+self._assert_equals_(self._interpret_("foo ^ Math cos: 0"),(1));
+self._assert_equals_(self._interpret_("foo ^ NonExistingVar"),nil);
 return self}, function($ctx1) {$ctx1.fill(self,"testGlobalVar",{},smalltalk.InterpreterTest)})},
 messageSends: ["assert:equals:", "interpret:"]}),
 smalltalk.InterpreterTest);

+ 6 - 3
js/Compiler-Tests.js

@@ -814,13 +814,16 @@ selector: "testGlobalVar",
 category: 'tests',
 fn: function (){
 var self=this;
+function $BlockClosure(){return smalltalk.BlockClosure||(typeof BlockClosure=="undefined"?nil:BlockClosure)}
 return smalltalk.withContext(function($ctx1) { 
-self._assert_equals_(self._interpret_("foo ^ console"),console);
+self._assert_equals_(self._interpret_("foo ^ eval class"),$BlockClosure());
+self._assert_equals_(self._interpret_("foo ^ Math cos: 0"),(1));
+self._assert_equals_(self._interpret_("foo ^ NonExistingVar"),nil);
 return self}, function($ctx1) {$ctx1.fill(self,"testGlobalVar",{},smalltalk.InterpreterTest)})},
 args: [],
-source: "testGlobalVar\x0a\x09self assert: (self interpret: 'foo ^ console') equals: console",
+source: "testGlobalVar\x0a\x09self assert: (self interpret: 'foo ^ eval class') equals: BlockClosure.\x0a\x09self assert: (self interpret: 'foo ^ Math cos: 0') equals: 1.\x0a\x09self assert: (self interpret: 'foo ^ NonExistingVar') equals: nil.",
 messageSends: ["assert:equals:", "interpret:"],
-referencedClasses: []
+referencedClasses: ["BlockClosure"]
 }),
 smalltalk.InterpreterTest);
 

+ 50 - 7
js/Kernel-Infrastructure.deploy.js

@@ -1228,15 +1228,29 @@ smalltalk.method({
 selector: "existsGlobal:",
 fn: function (aString){
 var self=this;
+function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
 return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st($PlatformInterface())._globals())._at_ifPresent_ifAbsent_(aString,(function(){
+return smalltalk.withContext(function($ctx2) {
+return true;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(){
+return smalltalk.withContext(function($ctx2) {
+return false;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"existsGlobal:",{aString:aString},smalltalk.PlatformInterface.klass)})},
+messageSends: ["at:ifPresent:ifAbsent:", "globals"]}),
+smalltalk.PlatformInterface.klass);
 
-	var f = new Function('aString',
-	'if (/^[0-9]/.test(aString) || !/^[\\w_]+$/.test(aString))\n'+
-	'	return false;\n'+
-	'try { eval(aString); return true; } catch (ex) {}\n'+
-	'return false;');
-	return f(aString);;
-return self}, function($ctx1) {$ctx1.fill(self,"existsGlobal:",{aString:aString},smalltalk.PlatformInterface.klass)})},
+smalltalk.addMethod(
+smalltalk.method({
+selector: "globals",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return (new Function('return this'))();;
+return self}, function($ctx1) {$ctx1.fill(self,"globals",{},smalltalk.PlatformInterface.klass)})},
 messageSends: []}),
 smalltalk.PlatformInterface.klass);
 
@@ -1411,6 +1425,24 @@ return self}, function($ctx1) {$ctx1.fill(self,"at:",{aString:aString},smalltalk
 messageSends: []}),
 smalltalk.Smalltalk);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "at:ifAbsent:",
+fn: function (aKey,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._includesKey_(aKey);
+$3=(function(){
+return smalltalk.withContext(function($ctx2) {
+return self._at_(aKey);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})});
+$1=_st($2)._ifTrue_ifFalse_($3,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aKey:aKey,aBlock:aBlock},smalltalk.Smalltalk)})},
+messageSends: ["ifTrue:ifFalse:", "includesKey:", "at:"]}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "basicParse:",
@@ -1508,6 +1540,17 @@ return self}, function($ctx1) {$ctx1.fill(self,"globalJsVariables",{},smalltalk.
 messageSends: []}),
 smalltalk.Smalltalk);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "includesKey:",
+fn: function (aKey){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self.hasOwnProperty(aKey);
+return self}, function($ctx1) {$ctx1.fill(self,"includesKey:",{aKey:aKey},smalltalk.Smalltalk)})},
+messageSends: []}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isSmalltalkObject:",

+ 67 - 9
js/Kernel-Infrastructure.js

@@ -1623,17 +1623,36 @@ selector: "existsGlobal:",
 category: 'actions',
 fn: function (aString){
 var self=this;
+function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
 return smalltalk.withContext(function($ctx1) { 
-
-	var f = new Function('aString',
-	'if (/^[0-9]/.test(aString) || !/^[\\w_]+$/.test(aString))\n'+
-	'	return false;\n'+
-	'try { eval(aString); return true; } catch (ex) {}\n'+
-	'return false;');
-	return f(aString);;
-return self}, function($ctx1) {$ctx1.fill(self,"existsGlobal:",{aString:aString},smalltalk.PlatformInterface.klass)})},
+var $1;
+$1=_st(_st($PlatformInterface())._globals())._at_ifPresent_ifAbsent_(aString,(function(){
+return smalltalk.withContext(function($ctx2) {
+return true;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(){
+return smalltalk.withContext(function($ctx2) {
+return false;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"existsGlobal:",{aString:aString},smalltalk.PlatformInterface.klass)})},
 args: ["aString"],
-source: "existsGlobal: aString\x0a<\x0a\x09var f = new Function('aString',\x0a\x09'if (/^[0-9]/.test(aString) || !/^[\x5c\x5cw_]+$/.test(aString))\x5cn'+\x0a\x09'\x09return false;\x5cn'+\x0a\x09'try { eval(aString); return true; } catch (ex) {}\x5cn'+\x0a\x09'return false;');\x0a\x09return f(aString);\x0a>",
+source: "existsGlobal: aString\x0a\x09^ PlatformInterface globals \x0a\x09\x09at: aString \x0a\x09\x09ifPresent: [ true ] \x0a\x09\x09ifAbsent: [ false ]",
+messageSends: ["at:ifPresent:ifAbsent:", "globals"],
+referencedClasses: ["PlatformInterface"]
+}),
+smalltalk.PlatformInterface.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "globals",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return (new Function('return this'))();;
+return self}, function($ctx1) {$ctx1.fill(self,"globals",{},smalltalk.PlatformInterface.klass)})},
+args: [],
+source: "globals\x0a\x09<return (new Function('return this'))();> ",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1867,6 +1886,29 @@ referencedClasses: []
 }),
 smalltalk.Smalltalk);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "at:ifAbsent:",
+category: 'accessing',
+fn: function (aKey,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._includesKey_(aKey);
+$3=(function(){
+return smalltalk.withContext(function($ctx2) {
+return self._at_(aKey);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})});
+$1=_st($2)._ifTrue_ifFalse_($3,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aKey:aKey,aBlock:aBlock},smalltalk.Smalltalk)})},
+args: ["aKey", "aBlock"],
+source: "at: aKey ifAbsent: aBlock\x0a\x09^ (self includesKey: aKey)\x0a\x09\x09ifTrue: [self at: aKey]\x0a\x09\x09ifFalse: aBlock",
+messageSends: ["ifTrue:ifFalse:", "includesKey:", "at:"],
+referencedClasses: []
+}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "basicParse:",
@@ -2004,6 +2046,22 @@ referencedClasses: []
 }),
 smalltalk.Smalltalk);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "includesKey:",
+category: 'accessing',
+fn: function (aKey){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self.hasOwnProperty(aKey);
+return self}, function($ctx1) {$ctx1.fill(self,"includesKey:",{aKey:aKey},smalltalk.Smalltalk)})},
+args: ["aKey"],
+source: "includesKey: aKey\x0a\x09<return self.hasOwnProperty(aKey)>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isSmalltalkObject:",

+ 4 - 7
st/Compiler-Interpreter.st

@@ -1044,7 +1044,9 @@ visitBlockNode: aNode
 !
 
 visitClassReferenceNode: aNode
-	self push: (Smalltalk current at: aNode value)
+	self push: (Smalltalk current 
+		at: aNode value 
+		ifAbsent: [ PlatformInterface globals at: aNode value ])
 !
 
 visitDynamicArrayNode: aNode
@@ -1105,18 +1107,13 @@ visitValueNode: aNode
 
 visitVariableNode: aNode
 	aNode binding isUnknownVar ifTrue: [
-		^ self push: (window at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].
+		^ self push: (PlatformInterface globals at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].
 		
 	self push: (aNode binding isInstanceVar
 		ifTrue: [ self context receiver instVarAt: aNode value ]
 		ifFalse: [ self context localAt: aNode value ])
 ! !
 
-!Interpreter methodsFor: 'xxxDoIt'!
-
-xxxDoIt ^[self step] value
-! !
-
 !Node methodsFor: '*Compiler-Interpreter'!
 
 interpreter: anInterpreter continue: aBlock

+ 3 - 1
st/Compiler-Tests.st

@@ -355,7 +355,9 @@ testDynamicDictionary
 !
 
 testGlobalVar
-	self assert: (self interpret: 'foo ^ console') equals: console
+	self assert: (self interpret: 'foo ^ eval class') equals: BlockClosure.
+	self assert: (self interpret: 'foo ^ Math cos: 0') equals: 1.
+	self assert: (self interpret: 'foo ^ NonExistingVar') equals: nil.
 !
 
 testInlinedJSStatement

+ 18 - 8
st/Kernel-Infrastructure.st

@@ -619,6 +619,10 @@ PlatformInterface class instanceVariableNames: 'worker'!
 
 !PlatformInterface class methodsFor: 'accessing'!
 
+globals
+	<return (new Function('return this'))();>
+!
+
 setWorker: anObject
 	worker := anObject
 ! !
@@ -644,14 +648,10 @@ confirm: aString
 !
 
 existsGlobal: aString
-<
-	var f = new Function('aString',
-	'if (/^[0-9]/.test(aString) || !!/^[\\w_]+$/.test(aString))\n'+
-	'	return false;\n'+
-	'try { eval(aString); return true; } catch (ex) {}\n'+
-	'return false;');
-	return f(aString);
->
+	^ PlatformInterface globals 
+		at: aString 
+		ifPresent: [ true ] 
+		ifAbsent: [ false ]
 !
 
 prompt: aString
@@ -749,6 +749,16 @@ at: aString
 	<return self[aString]>
 !
 
+at: aKey ifAbsent: aBlock
+	^ (self includesKey: aKey)
+		ifTrue: [self at: aKey]
+		ifFalse: aBlock
+!
+
+includesKey: aKey
+	<return self.hasOwnProperty(aKey)>
+!
+
 parse: aString
 	| result |