I have been playing around with implementing Module#class_eval, partly because I wanted to use it in a test case and partly because I thought it would help my understanding of the guts of IronRuby. I managed to get the following code to work but it is not pretty. [RubyMethod("class_eval")] public static object Evaluate(CodeContext/*!*/ context, RubyModule/*!*/ module, MutableString code) { // Create a new context for running the code string - not sure if this is necessary. CodeContext context2 = new CodeContext(context); // We need a localscope for GetRfc. RubyScope localScope = RubyUtils.GetScope(context); // Create a local scope for this module definition. // (This has a side-effect that context2 has the new module scope attached in its LocalScope property.) RubyScope moduleScope = RubyOps.CreateModuleScope(context2, localScope.RuntimeFlowControl, module); // Compile up the code in the new context SourceUnit sourceUnit context2.LanguageContext.CreateSnippet(code); ScriptCode scriptCode sourceUnit.Compile(context2.LanguageContext.GetModuleCompilerOptions(context 2.Scope), null); // Run the code in the new context. // (This overload is currently private but we need to be able to pass in the new context). return scriptCode.Run(context2, false); } I added superfluous comments for the benefit of posting it her. The main issue, as noted at the bottom of the code, is that the overload of ScriptCode.Run that is called is currently private. All the public overloads create a new CodeContext and you lose the LocalScope which is needed to ensure that the code is run in the context of the module being defined. Any comments on this? I assume that as the Hosting spec evolves this could get a lot cleaner. Is there a better way right now to achieve the same result? Also, one thing that really messed my head up for quite a while is the use of the word scope. It took me a while to come to terms with the fact that there are numerous completely separate scopes: Scope, ScopeExtension (which contains a Scope property), ScriptScope (which implements IScriptScope) and RubyScope (which derives from LocalScope). Am I right in saying: Scope is the global scope in which the current Ruby program is running (with ScopeExtension just wrapping that and ScriptScope being a container for code being run within that scope)? RubyScope is the local scope within a Ruby program that tells you things like what the current self object is and what variables are accessible? Regards, Pete http://ironingruby.blogspot.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20080114/371128ca/attachment-0001.html
Peter Bacon Darwin:> I have been playing around with implementing Module#class_eval, partly > because I wanted to use it in a test case and partly because I thought > it would help my understanding of the guts of IronRuby. I managed to > get the following code to work but it is not pretty. > > [RubyMethod("class_eval")] > public static object Evaluate(CodeContext/*!*/ context, > RubyModule/*!*/ module, MutableString code) { > > // Create a new context for running the code string - not > sure if this is necessary. > CodeContext context2 = new CodeContext(context); > > // We need a localscope for GetRfc. > RubyScope localScope = RubyUtils.GetScope(context); > > // Create a local scope for this module definition. > // (This has a side-effect that context2 has the new module > scope attached in its LocalScope property.) > RubyScope moduleScope = RubyOps.CreateModuleScope(context2, > localScope.RuntimeFlowControl, module); > > // Compile up the code in the new context > SourceUnit sourceUnit > context2.LanguageContext.CreateSnippet(code); > ScriptCode scriptCode > sourceUnit.Compile(context2.LanguageContext.GetModuleCompilerOptions(co > n > text2.Scope), null); > > // Run the code in the new context. > // (This overload is currently private but we need to be > able to pass in the new context). > return scriptCode.Run(context2, false); > > } > > I added superfluous comments for the benefit of posting it her. The > main issue, as noted at the bottom of the code, is that the overload of > ScriptCode.Run that is called is currently private. All the public > overloads create a new CodeContext and you lose the LocalScope which is > needed to ensure that the code is run in the context of the module > being defined. > > Any comments on this? I assume that as the Hosting spec evolves this > could get a lot cleaner. Is there a better way right now to achieve > the same result?Nice that you got that working! I think the main issue you''re running into is that hosting APIs are in flux. That''s been a delaying factor on getting all the string-based "evals" working. Also, there might be some more work in the compiler too; e.g. are we burning in references where we should be looking them up dynamically, etc. There might be other things that Tomas has in mind that need to be changed. Anyway, I think it makes sense for us to do all the eval-related stuff in one push.> Also, one thing that really messed my head up for quite a while is the > use of the word scope. It took me a while to come to terms with the > fact that there are numerous completely separate scopes: Scope, > ScopeExtension (which contains a Scope property), ScriptScope (which > implements IScriptScope) and RubyScope (which derives from LocalScope). > > Am I right in saying: > > Scope is the global scope in which the current Ruby program is running > (with ScopeExtension just wrapping that and ScriptScope being a > container for code being run within that scope)? > > RubyScope is the local scope within a Ruby program that tells you > things like what the current self object is and what variables are > accessible?I think that''s correct. Scope is the DLR global scope thing, while ScriptScope is the hosting API version. RubyScope will probably end up roughly equivalent to a binding (but it doesn''t have all the stuff yet--e.g. locals) - John
Well, evals are actually not blocked by hosting API (rather the opposite is true for Ruby hosting in console). There is some other stuff that needs to be done in DLR and also in Ruby compiler to make eval happen. I''m on it, but it will take some time. Tomas -----Original Message----- From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of John Messerly Sent: Friday, January 18, 2008 3:38 PM To: ironruby-core at rubyforge.org Subject: Re: [Ironruby-core] Module#class_eval Peter Bacon Darwin:> I have been playing around with implementing Module#class_eval, partly > because I wanted to use it in a test case and partly because I thought > it would help my understanding of the guts of IronRuby. I managed to > get the following code to work but it is not pretty. > > [RubyMethod("class_eval")] > public static object Evaluate(CodeContext/*!*/ context, > RubyModule/*!*/ module, MutableString code) { > > // Create a new context for running the code string - not > sure if this is necessary. > CodeContext context2 = new CodeContext(context); > > // We need a localscope for GetRfc. > RubyScope localScope = RubyUtils.GetScope(context); > > // Create a local scope for this module definition. > // (This has a side-effect that context2 has the new module > scope attached in its LocalScope property.) > RubyScope moduleScope = RubyOps.CreateModuleScope(context2, > localScope.RuntimeFlowControl, module); > > // Compile up the code in the new context > SourceUnit sourceUnit > context2.LanguageContext.CreateSnippet(code); > ScriptCode scriptCode > sourceUnit.Compile(context2.LanguageContext.GetModuleCompilerOptions(co > n > text2.Scope), null); > > // Run the code in the new context. > // (This overload is currently private but we need to be > able to pass in the new context). > return scriptCode.Run(context2, false); > > } > > I added superfluous comments for the benefit of posting it her. The > main issue, as noted at the bottom of the code, is that the overload of > ScriptCode.Run that is called is currently private. All the public > overloads create a new CodeContext and you lose the LocalScope which is > needed to ensure that the code is run in the context of the module > being defined. > > Any comments on this? I assume that as the Hosting spec evolves this > could get a lot cleaner. Is there a better way right now to achieve > the same result?Nice that you got that working! I think the main issue you''re running into is that hosting APIs are in flux. That''s been a delaying factor on getting all the string-based "evals" working. Also, there might be some more work in the compiler too; e.g. are we burning in references where we should be looking them up dynamically, etc. There might be other things that Tomas has in mind that need to be changed. Anyway, I think it makes sense for us to do all the eval-related stuff in one push.> Also, one thing that really messed my head up for quite a while is the > use of the word scope. It took me a while to come to terms with the > fact that there are numerous completely separate scopes: Scope, > ScopeExtension (which contains a Scope property), ScriptScope (which > implements IScriptScope) and RubyScope (which derives from LocalScope). > > Am I right in saying: > > Scope is the global scope in which the current Ruby program is running > (with ScopeExtension just wrapping that and ScriptScope being a > container for code being run within that scope)? > > RubyScope is the local scope within a Ruby program that tells you > things like what the current self object is and what variables are > accessible?I think that''s correct. Scope is the DLR global scope thing, while ScriptScope is the hosting API version. RubyScope will probably end up roughly equivalent to a binding (but it doesn''t have all the stuff yet--e.g. locals) - John _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core