Browse Source

fixes #832

Adds an Evaluator class and double-dispatch evaluation of code
Nicolas Petton 10 years ago
parent
commit
7735c06ec0

+ 134 - 0
src/Compiler-Core.js

@@ -687,6 +687,140 @@ globals.Compiler.klass);
 
 smalltalk.addClass('DoIt', globals.Object, [], 'Compiler-Core');
 globals.DoIt.comment="`DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "xxxDoIt",
+protocol: 'xxxDoIt',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._halt();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._value();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"xxxDoIt",{},globals.DoIt)})},
+args: [],
+source: "xxxDoIt ^ [ self halt ] value",
+messageSends: ["value", "halt"],
+referencedClasses: []
+}),
+globals.DoIt);
+
+
+
+smalltalk.addClass('Evaluator', globals.Object, [], 'Compiler-Core');
+globals.Evaluator.comment="I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluate:context:",
+protocol: 'evaluating',
+fn: function (aString,aContext){
+var self=this;
+var compiler,ast;
+function $Compiler(){return globals.Compiler||(typeof Compiler=="undefined"?nil:Compiler)}
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+function $AISemanticAnalyzer(){return globals.AISemanticAnalyzer||(typeof AISemanticAnalyzer=="undefined"?nil:AISemanticAnalyzer)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3,$4;
+var $early={};
+try {
+compiler=_st($Compiler())._new();
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
+ast=_st(compiler)._parseExpression_(aString);
+return ast;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(ex){
+return smalltalk.withContext(function($ctx2) {
+$1=self._alert_(_st(ex)._messageText());
+throw $early=[$1];
+}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})}));
+$2=_st($AISemanticAnalyzer())._on_(_st(_st(aContext)._receiver())._class());
+_st($2)._context_(aContext);
+$3=_st($2)._visit_(ast);
+$4=_st(aContext)._evaluateNode_(ast);
+return $4;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"evaluate:context:",{aString:aString,aContext:aContext,compiler:compiler,ast:ast},globals.Evaluator)})},
+args: ["aString", "aContext"],
+source: "evaluate: aString context: aContext\x0a\x09\x22Similar to #evaluate:for:, with the following differences:\x0a\x09- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`\x0a\x09- instead of evaluating against a receiver, evaluate in the context of `aContext`\x22\x0a\x0a\x09| compiler ast |\x0a\x09\x0a\x09compiler := Compiler new.\x0a\x09[ ast := compiler parseExpression: aString ] \x0a\x09\x09on: Error \x0a\x09\x09do: [ :ex | ^ self alert: ex messageText ].\x0a\x09\x09\x0a\x09(AISemanticAnalyzer on: aContext receiver class)\x0a\x09\x09context: aContext;\x0a\x09\x09visit: ast.\x0a\x0a\x09^ aContext evaluateNode: ast",
+messageSends: ["new", "on:do:", "parseExpression:", "alert:", "messageText", "context:", "on:", "class", "receiver", "visit:", "evaluateNode:"],
+referencedClasses: ["Compiler", "Error", "AISemanticAnalyzer"]
+}),
+globals.Evaluator);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluate:for:",
+protocol: 'evaluating',
+fn: function (aString,anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(anObject)._evaluate_on_(aString,self);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"evaluate:for:",{aString:aString,anObject:anObject},globals.Evaluator)})},
+args: ["aString", "anObject"],
+source: "evaluate: aString for: anObject\x0a\x09^ anObject evaluate: aString on: self",
+messageSends: ["evaluate:on:"],
+referencedClasses: []
+}),
+globals.Evaluator);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluate:receiver:",
+protocol: 'evaluating',
+fn: function (aString,anObject){
+var self=this;
+var compiler;
+function $Compiler(){return globals.Compiler||(typeof Compiler=="undefined"?nil:Compiler)}
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+var $early={};
+try {
+compiler=_st($Compiler())._new();
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(compiler)._parseExpression_(aString);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(ex){
+return smalltalk.withContext(function($ctx2) {
+$1=self._alert_(_st(ex)._messageText());
+throw $early=[$1];
+}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})}));
+$2=_st(compiler)._evaluateExpression_on_(aString,anObject);
+return $2;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"evaluate:receiver:",{aString:aString,anObject:anObject,compiler:compiler},globals.Evaluator)})},
+args: ["aString", "anObject"],
+source: "evaluate: aString receiver: anObject\x0a\x09| compiler |\x0a\x09\x0a\x09compiler := Compiler new.\x0a\x09[ compiler parseExpression: aString ] \x0a\x09\x09on: Error \x0a\x09\x09do: [ :ex | ^ self alert: ex messageText ].\x0a\x0a\x09^ compiler evaluateExpression: aString on: anObject",
+messageSends: ["new", "on:do:", "parseExpression:", "alert:", "messageText", "evaluateExpression:on:"],
+referencedClasses: ["Compiler", "Error"]
+}),
+globals.Evaluator);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluate:for:",
+protocol: 'instance creation',
+fn: function (aString,anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._new())._evaluate_for_(aString,anObject);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"evaluate:for:",{aString:aString,anObject:anObject},globals.Evaluator.klass)})},
+args: ["aString", "anObject"],
+source: "evaluate: aString for: anObject\x0a\x09^ self new evaluate: aString for: anObject",
+messageSends: ["evaluate:for:", "new"],
+referencedClasses: []
+}),
+globals.Evaluator.klass);
 
 
 smalltalk.addClass('NodeVisitor', globals.Object, [], 'Compiler-Core');

+ 53 - 0
src/Compiler-Core.st

@@ -223,6 +223,59 @@ Object subclass: #DoIt
 !DoIt commentStamp!
 `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
 
+!DoIt methodsFor: 'xxxDoIt'!
+
+xxxDoIt ^ [ self halt ] value
+! !
+
+Object subclass: #Evaluator
+	instanceVariableNames: ''
+	package: 'Compiler-Core'!
+!Evaluator commentStamp!
+I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
+
+!Evaluator methodsFor: 'evaluating'!
+
+evaluate: aString context: aContext
+	"Similar to #evaluate:for:, with the following differences:
+	- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
+	- instead of evaluating against a receiver, evaluate in the context of `aContext`"
+
+	| compiler ast |
+	
+	compiler := Compiler new.
+	[ ast := compiler parseExpression: aString ] 
+		on: Error 
+		do: [ :ex | ^ self alert: ex messageText ].
+		
+	(AISemanticAnalyzer on: aContext receiver class)
+		context: aContext;
+		visit: ast.
+
+	^ aContext evaluateNode: ast
+!
+
+evaluate: aString for: anObject
+	^ anObject evaluate: aString on: self
+!
+
+evaluate: aString receiver: anObject
+	| compiler |
+	
+	compiler := Compiler new.
+	[ compiler parseExpression: aString ] 
+		on: Error 
+		do: [ :ex | ^ self alert: ex messageText ].
+
+	^ compiler evaluateExpression: aString on: anObject
+! !
+
+!Evaluator class methodsFor: 'instance creation'!
+
+evaluate: aString for: anObject
+	^ self new evaluate: aString for: anObject
+! !
+
 Object subclass: #NodeVisitor
 	instanceVariableNames: ''
 	package: 'Compiler-Core'!

+ 18 - 0
src/Compiler-Interpreter.js

@@ -296,6 +296,24 @@ referencedClasses: []
 }),
 globals.AIContext);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluate:on:",
+protocol: 'evaluating',
+fn: function (aString,anEvaluator){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(anEvaluator)._evaluate_context_(aString,self);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"evaluate:on:",{aString:aString,anEvaluator:anEvaluator},globals.AIContext)})},
+args: ["aString", "anEvaluator"],
+source: "evaluate: aString on: anEvaluator\x0a\x09^ anEvaluator evaluate: aString context: self",
+messageSends: ["evaluate:context:"],
+referencedClasses: []
+}),
+globals.AIContext);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "evaluateNode:",

+ 4 - 0
src/Compiler-Interpreter.st

@@ -194,6 +194,10 @@ sendIndexes: aDictionary
 
 !AIContext methodsFor: 'evaluating'!
 
+evaluate: aString on: anEvaluator
+	^ anEvaluator evaluate: aString context: self
+!
+
 evaluateNode: aNode
 	^ ASTInterpreter new
 		context: self;

+ 21 - 3
src/Helios-Debugger.js

@@ -20,6 +20,24 @@ referencedClasses: []
 }),
 globals.HLContextInspectorDecorator);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluate:on:",
+protocol: 'evaluating',
+fn: function (aString,anEvaluator){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._context())._evaluate_on_(aString,anEvaluator);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"evaluate:on:",{aString:aString,anEvaluator:anEvaluator},globals.HLContextInspectorDecorator)})},
+args: ["aString", "anEvaluator"],
+source: "evaluate: aString on: anEvaluator\x0a\x09^ self context evaluate: aString on: anEvaluator",
+messageSends: ["evaluate:on:", "context"],
+referencedClasses: []
+}),
+globals.HLContextInspectorDecorator);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "initializeFromContext:",
@@ -809,12 +827,12 @@ fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self._environment())._interpret_inContext_(aString,self._currentContext());
+$1=_st(self._environment())._evaluateString_on_(aString,self._currentContext());
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"evaluate:",{aString:aString},globals.HLDebuggerModel)})},
 args: ["aString"],
-source: "evaluate: aString\x0a\x09^ self environment \x0a\x09\x09interpret: aString \x0a\x09\x09inContext: self currentContext",
-messageSends: ["interpret:inContext:", "environment", "currentContext"],
+source: "evaluate: aString\x0a\x09^ self environment \x0a\x09\x09evaluateString: aString \x0a\x09\x09on: self currentContext",
+messageSends: ["evaluateString:on:", "environment", "currentContext"],
 referencedClasses: []
 }),
 globals.HLDebuggerModel);

+ 8 - 2
src/Helios-Debugger.st

@@ -9,6 +9,12 @@ context
 	^ context
 ! !
 
+!HLContextInspectorDecorator methodsFor: 'evaluating'!
+
+evaluate: aString on: anEvaluator
+	^ self context evaluate: aString on: anEvaluator
+! !
+
 !HLContextInspectorDecorator methodsFor: 'initialization'!
 
 initializeFromContext: aContext
@@ -341,8 +347,8 @@ where
 
 evaluate: aString
 	^ self environment 
-		interpret: aString 
-		inContext: self currentContext
+		evaluateString: aString 
+		on: self currentContext
 ! !
 
 !HLDebuggerModel methodsFor: 'initialization'!

+ 3 - 3
src/Helios-Workspace.js

@@ -73,7 +73,7 @@ return smalltalk.withContext(function($ctx1) {
 var $1;
 $1=_st((function(){
 return smalltalk.withContext(function($ctx2) {
-return _st(self._environment())._eval_on_(aString,self._receiver());
+return _st(self._environment())._evaluateString_on_(aString,self._receiver());
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._tryCatch_((function(e){
 return smalltalk.withContext(function($ctx2) {
 _st($ErrorHandler())._handleError_(e);
@@ -82,8 +82,8 @@ return nil;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"doIt:",{aString:aString},globals.HLCodeModel)})},
 args: ["aString"],
-source: "doIt: aString\x0a\x09\x22Evaluate aString in the receiver's `environment`.\x0a\x09\x0a\x09Note: Catch any error and handle it manually, bypassing\x0a\x09boot.js behavior to avoid the browser default action on\x0a\x09ctrl+d/ctrl+p.\x0a\x09\x0a\x09See https://github.com/amber-smalltalk/amber/issues/882\x22\x0a\x0a\x09^ [ self environment eval: aString on: self receiver ]\x0a\x09\x09tryCatch: [ :e | \x0a\x09\x09\x09ErrorHandler handleError: e.\x0a\x09\x09\x09nil ]",
-messageSends: ["tryCatch:", "eval:on:", "environment", "receiver", "handleError:"],
+source: "doIt: aString\x0a\x09\x22Evaluate aString in the receiver's `environment`.\x0a\x09\x0a\x09Note: Catch any error and handle it manually, bypassing\x0a\x09boot.js behavior to avoid the browser default action on\x0a\x09ctrl+d/ctrl+p.\x0a\x09\x0a\x09See https://github.com/amber-smalltalk/amber/issues/882\x22\x0a\x0a\x09^ [ self environment evaluateString: aString on: self receiver ]\x0a\x09\x09tryCatch: [ :e | \x0a\x09\x09\x09ErrorHandler handleError: e.\x0a\x09\x09\x09nil ]",
+messageSends: ["tryCatch:", "evaluateString:on:", "environment", "receiver", "handleError:"],
 referencedClasses: ["ErrorHandler"]
 }),
 globals.HLCodeModel);

+ 1 - 1
src/Helios-Workspace.st

@@ -40,7 +40,7 @@ doIt: aString
 	
 	See https://github.com/amber-smalltalk/amber/issues/882"
 
-	^ [ self environment eval: aString on: self receiver ]
+	^ [ self environment evaluateString: aString on: self receiver ]
 		tryCatch: [ :e | 
 			ErrorHandler handleError: e.
 			nil ]

+ 32 - 67
src/Kernel-Infrastructure.js

@@ -432,15 +432,15 @@ function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
 return smalltalk.withContext(function($ctx1) { 
 _st((function(){
 return smalltalk.withContext(function($ctx2) {
-return self._eval_on_(aString,_st($DoIt())._new());
+return self._evaluateString_on_(aString,_st($DoIt())._new());
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(error){
 return smalltalk.withContext(function($ctx2) {
 return self._alert_(_st(error)._messageText());
 }, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,2)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"compileClassDefinition:",{aString:aString},globals.Environment)})},
 args: ["aString"],
-source: "compileClassDefinition: aString\x0a\x09[ self eval: aString on: DoIt new ]\x0a\x09\x09on: Error\x0a\x09\x09do: [ :error | self alert: error messageText ]",
-messageSends: ["on:do:", "eval:on:", "new", "alert:", "messageText"],
+source: "compileClassDefinition: aString\x0a\x09[ self evaluateString: aString on: DoIt new ]\x0a\x09\x09on: Error\x0a\x09\x09do: [ :error | self alert: error messageText ]",
+messageSends: ["on:do:", "evaluateString:on:", "new", "alert:", "messageText"],
 referencedClasses: ["DoIt", "Error"]
 }),
 globals.Environment);
@@ -513,33 +513,18 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "eval:on:",
 protocol: 'evaluating',
-fn: function (aString,aReceiver){
+fn: function (aString,anObject){
 var self=this;
-var compiler;
-function $Compiler(){return globals.Compiler||(typeof Compiler=="undefined"?nil:Compiler)}
-function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+function $Evaluator(){return globals.Evaluator||(typeof Evaluator=="undefined"?nil:Evaluator)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-var $early={};
-try {
-compiler=_st($Compiler())._new();
-_st((function(){
-return smalltalk.withContext(function($ctx2) {
-return _st(compiler)._parseExpression_(aString);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(ex){
-return smalltalk.withContext(function($ctx2) {
-$1=self._alert_(_st(ex)._messageText());
-throw $early=[$1];
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})}));
-$2=_st(compiler)._evaluateExpression_on_(aString,aReceiver);
-return $2;
-}
-catch(e) {if(e===$early)return e[0]; throw e}
-}, function($ctx1) {$ctx1.fill(self,"eval:on:",{aString:aString,aReceiver:aReceiver,compiler:compiler},globals.Environment)})},
-args: ["aString", "aReceiver"],
-source: "eval: aString on: aReceiver\x0a\x09| compiler |\x0a\x09compiler := Compiler new.\x0a\x09[ compiler parseExpression: aString ] on: Error do: [ :ex |\x0a\x09\x09^ self alert: ex messageText ].\x0a\x09^ compiler evaluateExpression: aString on: aReceiver",
-messageSends: ["new", "on:do:", "parseExpression:", "alert:", "messageText", "evaluateExpression:on:"],
-referencedClasses: ["Compiler", "Error"]
+var $1;
+$1=_st($Evaluator())._evaluate_on_(aString,anObject);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"eval:on:",{aString:aString,anObject:anObject},globals.Environment)})},
+args: ["aString", "anObject"],
+source: "eval: aString on: anObject\x0a\x09^ Evaluator evaluate: aString on: anObject",
+messageSends: ["evaluate:on:"],
+referencedClasses: ["Evaluator"]
 }),
 globals.Environment);
 
@@ -568,6 +553,25 @@ referencedClasses: []
 }),
 globals.Environment);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluateString:on:",
+protocol: 'evaluating',
+fn: function (aString,anObject){
+var self=this;
+function $Evaluator(){return globals.Evaluator||(typeof Evaluator=="undefined"?nil:Evaluator)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($Evaluator())._evaluate_for_(aString,anObject);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"evaluateString:on:",{aString:aString,anObject:anObject},globals.Environment)})},
+args: ["aString", "anObject"],
+source: "evaluateString: aString on: anObject\x0a\x09^ Evaluator evaluate: aString for: anObject",
+messageSends: ["evaluate:for:"],
+referencedClasses: ["Evaluator"]
+}),
+globals.Environment);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "inspect:",
@@ -585,45 +589,6 @@ referencedClasses: ["Inspector"]
 }),
 globals.Environment);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "interpret:inContext:",
-protocol: 'evaluating',
-fn: function (aString,anAIContext){
-var self=this;
-var compiler,ast;
-function $Compiler(){return globals.Compiler||(typeof Compiler=="undefined"?nil:Compiler)}
-function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
-function $AISemanticAnalyzer(){return globals.AISemanticAnalyzer||(typeof AISemanticAnalyzer=="undefined"?nil:AISemanticAnalyzer)}
-return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4;
-var $early={};
-try {
-compiler=_st($Compiler())._new();
-_st((function(){
-return smalltalk.withContext(function($ctx2) {
-ast=_st(compiler)._parseExpression_(aString);
-return ast;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(ex){
-return smalltalk.withContext(function($ctx2) {
-$1=self._alert_(_st(ex)._messageText());
-throw $early=[$1];
-}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1,2)})}));
-$2=_st($AISemanticAnalyzer())._on_(_st(_st(anAIContext)._receiver())._class());
-_st($2)._context_(anAIContext);
-$3=_st($2)._visit_(ast);
-$4=_st(anAIContext)._evaluateNode_(ast);
-return $4;
-}
-catch(e) {if(e===$early)return e[0]; throw e}
-}, function($ctx1) {$ctx1.fill(self,"interpret:inContext:",{aString:aString,anAIContext:anAIContext,compiler:compiler,ast:ast},globals.Environment)})},
-args: ["aString", "anAIContext"],
-source: "interpret: aString inContext: anAIContext\x0a\x09\x22Similar to #eval:on:, with the following differences:\x0a\x09- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`\x0a\x09- instead of evaluating against a receiver, evaluate in the context of `anAIContext`\x22\x0a\x0a\x09| compiler ast |\x0a\x09compiler := Compiler new.\x0a\x09[ ast := compiler parseExpression: aString ] on: Error do: [ :ex |\x0a\x09\x09^ self alert: ex messageText ].\x0a\x09(AISemanticAnalyzer on: anAIContext receiver class)\x0a\x09\x09context: anAIContext;\x0a\x09\x09visit: ast.\x0a\x09^ anAIContext evaluateNode: ast",
-messageSends: ["new", "on:do:", "parseExpression:", "alert:", "messageText", "context:", "on:", "class", "receiver", "visit:", "evaluateNode:"],
-referencedClasses: ["Compiler", "Error", "AISemanticAnalyzer"]
-}),
-globals.Environment);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "moveClass:toPackage:",

+ 7 - 22
src/Kernel-Infrastructure.st

@@ -226,7 +226,7 @@ compileClassComment: aString for: aClass
 !
 
 compileClassDefinition: aString
-	[ self eval: aString on: DoIt new ]
+	[ self evaluateString: aString on: DoIt new ]
 		on: Error
 		do: [ :error | self alert: error messageText ]
 !
@@ -250,27 +250,12 @@ evaluate: aBlock on: anErrorClass do: exceptionBlock
 
 !Environment methodsFor: 'evaluating'!
 
-eval: aString on: aReceiver
-	| compiler |
-	compiler := Compiler new.
-	[ compiler parseExpression: aString ] on: Error do: [ :ex |
-		^ self alert: ex messageText ].
-	^ compiler evaluateExpression: aString on: aReceiver
-!
-
-interpret: aString inContext: anAIContext
-	"Similar to #eval:on:, with the following differences:
-	- instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
-	- instead of evaluating against a receiver, evaluate in the context of `anAIContext`"
-
-	| compiler ast |
-	compiler := Compiler new.
-	[ ast := compiler parseExpression: aString ] on: Error do: [ :ex |
-		^ self alert: ex messageText ].
-	(AISemanticAnalyzer on: anAIContext receiver class)
-		context: anAIContext;
-		visit: ast.
-	^ anAIContext evaluateNode: ast
+eval: aString on: anObject
+	^ Evaluator evaluate: aString on: anObject
+!
+
+evaluateString: aString on: anObject
+	^ Evaluator evaluate: aString for: anObject
 ! !
 
 !Environment methodsFor: 'services'!

+ 18 - 0
src/Kernel-Objects.js

@@ -97,6 +97,24 @@ referencedClasses: ["MessageNotUnderstood"]
 }),
 globals.ProtoObject);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "evaluate:on:",
+protocol: 'evaluating',
+fn: function (aString,anEvaluator){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(anEvaluator)._evaluate_receiver_(aString,self);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"evaluate:on:",{aString:aString,anEvaluator:anEvaluator},globals.ProtoObject)})},
+args: ["aString", "anEvaluator"],
+source: "evaluate: aString on: anEvaluator\x0a\x09^ anEvaluator evaluate: aString receiver: self",
+messageSends: ["evaluate:receiver:"],
+referencedClasses: []
+}),
+globals.ProtoObject);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "identityHash",

+ 6 - 0
src/Kernel-Objects.st

@@ -68,6 +68,12 @@ doesNotUnderstand: aMessage
 		signal
 ! !
 
+!ProtoObject methodsFor: 'evaluating'!
+
+evaluate: aString on: anEvaluator
+	^ anEvaluator evaluate: aString receiver: self
+! !
+
 !ProtoObject methodsFor: 'initialization'!
 
 initialize