This might be possible.  If you wrap this all up in a PythonAst object (calling 
the constructor which takes a CompilerContext), call Bind on it then you should 
get a LambdaExpression back out.  You can Compile() on that.

But it’s not like this is well traveled territory and this only applies to 
2.6.1 (before that the trees weren’t DLR ASTs so they weren’t reducable).  When 
we do this ourselves we also call the produced delegate and flow in some data.  
The delegate is going to want at least a FunctionCode object as an argument but 
I think you could get away with passing null (at least as long as no exceptions 
are thrown).  The delegate might also want a CodeContext object as well 
depending on the compilation mode we end up using (which is based on the 
CompilerContext you give us).  This you wouldn’t be able to get away w/ passing 
null.  But you can get one by doing new ModuleContext(new PythonDictionary(), 
pythonContext).GlobalContext.  The HostingHelpers class can give you a 
LanguageContext from the ScriptEngine for Python which you can cast to a 
PythonContext.

Let me know if it works! ☺

From: users-boun...@lists.ironpython.com 
[mailto:users-boun...@lists.ironpython.com] On Behalf Of Justin Chase
Sent: Monday, April 12, 2010 4:09 PM
To: Discussion of IronPython
Subject: Re: [IronPython] Building via AST

Ok, so at risk of being a nuissance I have one last question because I feel 
like I'm half way there. I have the following example that seems to work:

# sample.py
from ConsoleApplication4 import IExample

class Example(IExample):
          test = "hello python"
          def Do(self):
                      return self.test

# program.cs
namespace ConsoleApplication4
{
          class Program
          {
                      static void Main(string[] args)
                      {
                                  var runtime = Python.CreateRuntime();
                                  
runtime.LoadAssembly(typeof(IExample).Assembly);

                                  dynamic python = runtime.UseFile("sample.py");
                                  IExample example = (IExample)python.Example();

                                  Console.WriteLine(example.Do());
                                  Console.ReadKey(true);
                      }
          }

          public interface IExample
          {
                      string Do();
          }
}

Which prints out "hello python" as expected and is the exact behavior I would 
like to have. So now, say I did this instead:

# program.cs
namespace ConsoleApplication4
{
          class Program
          {
                      static void Main(string[] args)
                      {
                                  var runtime = Python.CreateRuntime();
                                  
runtime.LoadAssembly(typeof(IExample).Assembly);

                                  var import = new 
IronPython.Compiler.Ast.ImportStatement(
                                              new[] { new ModuleName(new[] { 
"ConsoleApplication4" }) },
                                              new[] { "IExample" },
                                              false);

                                  var classDefinition = new 
IronPython.Compiler.Ast.ClassDefinition("Example",
                                              new Expression[] { new 
NameExpression("IExample") },
                                              new FunctionDefinition(
                                                          "Do",
                                                          new[] { new 
Parameter("self") },
                                                          new 
ReturnStatement(new ConstantExpression("hello python!"))));

                                  // TODO: Compile the above AST into something!
                                  dynamic python = null;

                                  IExample example = (IExample)python.Example();
                                  Console.WriteLine(example.Do());

                                  Console.ReadKey(true);
                      }
          }

          public interface IExample
          {
                      string Do();
          }
}

Is there anyway to fill in the line below the TODO such that I will get the 
exact same behavior as the first example? If you say no this time then I'll 
finally stop asking you questions (except maybe why not :-P). If you do say no 
this time, then I might be interested in trying to extend things such that it 
is possible.

On Mon, Apr 12, 2010 at 5:20 PM, Dino Viehland 
<di...@microsoft.com<mailto:di...@microsoft.com>> wrote:
Yes – there is the TypeGen class but really it’s just a thin wrapper around 
TypeBuilder w/ some helper APIs.  If we were to implement it today it might 
just be extension methods instead of a wrapper class.

Unfortunately there is currently no way to go from an expression tree to an 
instance method.  It’s on the top of the things to fix in the DLR for a future 
.NET release.  It’s sad that it hasn’t been solved yet but that is the state of 
the world.  If you really wanted to get crazy you could look at forking the DLR 
expression tree compiler and adding support ☺

As far as how Python does this – we do generate classes and we do this via our 
NewTypeMaker class.  But the IL that we create is rather minimal.  We just 
derive and override every virtual method and have it dispatch either to the 
method defined in a PythonType type (which is stored as an instance field in 
the object).  So while it sucks that we need to generate the IL by hand it’s 
small enough that it’s not a big deal.

From: 
users-boun...@lists.ironpython.com<mailto:users-boun...@lists.ironpython.com> 
[mailto:users-boun...@lists.ironpython.com<mailto:users-boun...@lists.ironpython.com>]
 On Behalf Of Justin Chase
Sent: Monday, April 12, 2010 2:03 PM
To: Discussion of IronPython
Subject: Re: [IronPython] Building via AST

Ok so I'm wondering if I'm perhaps using the wrong words to try to say what I 
mean. Because when I look into the IronPython source code I see a class called 
Microsoft.Scripting.Generation.TypeGen 
(http://ironpython.codeplex.com/SourceControl/changeset/view/65328#1011039). 
Which appears to be code for generating a .net type contrary to your response. 
Am I misinterpreting that?

Thanks for your examples below but that is about as far as I have gotten 
already, what I need is a way to actually generate types and instances members. 
And I was just looking at the ILGen class and all it's interesting helpers but 
what I'd really love to find is a way to generate this by just giving it an AST 
(including "this" references) instead of having to mess around with IL (hasn't 
this been solved already??).

I know that Python has a "class" construct and that if I compile scripts I can 
create instances of these objects, does this translate into actual .net types 
under the hood? Or something else? Can you add attributes or annotations to 
these classes for example? For my grand finale what I would really like to do 
is to generate types that implement interfaces and load them via MEF (by means 
of the Export attribute). Is this just the wrong way to be thinking about this 
entirely? Or am I just missing something?


On Mon, Apr 12, 2010 at 3:33 PM, Dino Viehland 
<di...@microsoft.com<mailto:di...@microsoft.com>> wrote:
Nope – the DLR doesn’t have any support for building .NET types – dynamic or 
otherwise.  If you’d like to just build an object which behaves dynamically I’d 
suggest looking at DynamicObject.  You can just subclass it and override 
various Try* methods and you’ll have a dynamic object.

If you really do need to do ILGen into a type, and as long as you’re building 
only static methods, you can use expression trees via Lambda<T>.CompileToMethod 
(unfortunately currently instance methods are not supported).  Here’s an 
example of that:

using System;
using System.Linq.Expressions;
using System.Reflection;

class Foo {
    public static void Main(string[] args) {
        var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new 
AssemblyName("foo"), System.Reflection.Emit.AssemblyBuilderAccess.Save);
        var module = asm.DefineDynamicModule("foo.dll");
        var type = module.DefineType("TestType");

        var param1 = Expression.Parameter(typeof(Foox), "arg1");
        var param2 = Expression.Parameter(typeof(Foox), "arg2");
        var method = type.DefineMethod("TestMethod", MethodAttributes.Public | 
MethodAttributes.Static);

        Expression.Lambda<Func<Foox, Foox, bool>>(
            Expression.Equal(param1, param2),
            new[] { param1, param2 }
        ).CompileToMethod(method);
        type.CreateType();
        asm.Save("foo.dll");
    }
}
enum Foox {
    Bar,
    Baz
}

From: 
users-boun...@lists.ironpython.com<mailto:users-boun...@lists.ironpython.com> 
[mailto:users-boun...@lists.ironpython.com<mailto:users-boun...@lists.ironpython.com>]
 On Behalf Of Justin Chase
Sent: Monday, April 12, 2010 1:21 PM
To: users@lists.ironpython.com<mailto:users@lists.ironpython.com>
Subject: [IronPython] Building via AST

Suppose I would like to build an AST programmatically and compile that into an 
assembly dynamically (meaning an assembly flagged with RunAndCollect) from C#. 
How would I do that with IronPython's help? I do not what to author Python code 
and compile that I would like to just deal directly with the AST.

Currently I have working code where I'm using System.Linq.Expression namespace 
to build statements and expressions into delegates but what I would like is to 
leverage the DLR to build dynamic types as well (without having to use 
ILGenerator preferably). Is this possible today?

--
Justin Chase
http://www.justnbusiness.com

_______________________________________________
Users mailing list
Users@lists.ironpython.com<mailto:Users@lists.ironpython.com>
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com



--
Justin Chase
http://www.justnbusiness.com

_______________________________________________
Users mailing list
Users@lists.ironpython.com<mailto:Users@lists.ironpython.com>
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com



--
Justin Chase
http://www.justnbusiness.com
_______________________________________________
Users mailing list
Users@lists.ironpython.com
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com

Reply via email to