SUCCESS! Here's the final code: var runtime = Python.CreateRuntime();
var functionDefinition = new FunctionDefinition( "Do", new[] { new Parameter("self") }, new ReturnStatement(new ConstantExpression("hello python!"))); var classDefinition = new IronPython.Compiler.Ast.ClassDefinition( "Example", new Expression[] { }, functionDefinition); dynamic python = runtime.Compile(classDefinition); dynamic example = python.Example(); Console.WriteLine(example.Do()); Console.ReadKey(true); public static class DLRHelper { public static dynamic Compile(this ScriptRuntime runtime, params Statement[] statements) { var engine = runtime.GetEngineByFileExtension(".py"); var context = (PythonContext)HostingHelpers.GetLanguageContext(engine); var globals = new PythonDictionary(); globals.Add("__name__", "<dynamic>"); var options = new PythonCompilerOptions(ModuleOptions.ExecOrEvalCode); var unit = new SourceUnit(context, NullTextContentProvider.Null, "", SourceCodeKind.AutoDetect); var moduleContext = new ModuleContext(globals, context); var codeContext = moduleContext.GlobalContext; var pythonAst = new PythonAst( new IronPython.Compiler.Ast.SuiteStatement(statements), false, ModuleOptions.ExecOrEvalCode, false, new CompilerContext( unit, options, ErrorSink.Default)); pythonAst.Walk(new EnsureLocWalker()); pythonAst.Bind(); var lambda = (System.Linq.Expressions.LambdaExpression)pythonAst.Reduce(); var func = (Func<CodeContext, FunctionCode, object>)lambda.Compile(); var result = func(codeContext, null); // result is null return HostingHelpers.CreateScriptScope(engine, codeContext.GlobalScope); } // I created a walker called EnsureLocWalker that overrides all Walk methods and calls SetLoc to new SourceSpan(new SourceLocation(1, 1, 1), new SourceLocation(2, 2, 2)); // and header when appropriate to new SourceLocation(1, 1, 1) } FYI your WithStatement, TryStatement and ForStatement are missing getters on their header property. That's frustrating. I want to be able to do this: if (node.Header == SourceLocation.Invalid) node.Header = new SourceLocation(1, 1, 1); Also it would be nice if the headers and locations were completely ignored if they're invalid instead of throwing exceptions. Also it would be *reaaaally *nice if you had a Walk(Node node) override on the PythonWalker. So you could do something to all nodes. Also, why have a million overrides for this? Can't you just make a generic PythonWalker? Then just have a single Walk(T node) and AfterWalk(T node). That would be a lot less gross. The reason why I want to do this is because I am working on a DSL tool ( http://metasharp.codeplex.com) where I'm compiling down into an AST. Currently I have transforms to create CodeDom objects and linq Expression objects but I lack the ability to dynamically create Types or directly generate IL. Using this I think i can save a TON of work for myself. Thanks for all the help! On Wed, Apr 14, 2010 at 6:21 PM, Dino Viehland <di...@microsoft.com> wrote: > Try calling SetLoc on the FunctionDefinition and also try setting the > Header property. I think if it’s some reasonable span it’ll work. > > > > *From:* users-boun...@lists.ironpython.com [mailto: > users-boun...@lists.ironpython.com] *On Behalf Of *Justin Chase > *Sent:* Wednesday, April 14, 2010 3:35 PM > > *To:* Discussion of IronPython > *Subject:* Re: [IronPython] Building via AST > > > > Ok awesome! > > > > So now I have: > > dynamic example = globals["Example"]; > > dynamic instance = example(); > > Console.WriteLine(instance.Do()); > > > > But I'm getting an exception about a line number. Any idea how I can get > past that? I've tried a bunch of things but I'm not sure what's going on. > > > > ArgumentOutOfRangeException > > Specified argument was out of the range of valid values. Parameter name: > line must be greater than or equal to 1 > > at Microsoft.Scripting.SourceLocation.ValidateLocation(Int32 index, > Int32 line, Int32 column) > > at Microsoft.Scripting.SourceLocation..ctor(Int32 index, Int32 line, > Int32 column) > > at IronPython.Compiler.Ast.FunctionDefinition.CreateFunctionLambda() > > at IronPython.Compiler.Ast.FunctionDefinition.EnsureFunctionLambda() > > at IronPython.Compiler.Ast.FunctionDefinition.GetLambda() > > at IronPython.Runtime.FunctionCode.get_Code() > > at IronPython.Runtime.FunctionCode.GetGeneratorOrNormalLambda() > > at IronPython.Runtime.FunctionCode.UpdateDelegate(PythonContext context, > Boolean forceCreation) > > at IronPython.Runtime.FunctionCode.LazyCompileFirstTarget(PythonFunction > function) > > at > IronPython.Compiler.PythonCallTargets.OriginalCallTarget1(PythonFunction > function, Object arg0) > > at IronPython.Runtime.PythonFunction.FunctionCaller`1.Call1(CallSite > site, CodeContext context, Object func, T0 arg0) > > at > System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite > site, T0 arg0, T1 arg1, T2 arg2) > > at CallSite.Target(Closure , CallSite , Object ) > > at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite > site, T0 arg0) > > at CallSite.Target(Closure , CallSite , Object ) > > at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite > site, T0 arg0) > > > > > > On Wed, Apr 14, 2010 at 3:32 PM, Dino Viehland <di...@microsoft.com> > wrote: > > The problem here is just that you actually have a nested code context when > for the top-level code you just need a single global context. Replace the > line: > > > > var codeContext = new CodeContext( > > new PythonDictionary(), > > moduleContext); > > > > with: > > var codeContext = moduleContext.GlobalContext; > > > > and it’ll work. The nested code context that you’re creating is only used > for when we’re inside of a function definition or a class definition. > > > > Also you can avoid creating the script scope and just pull Example out of > the globals dictionary as well. > > > > *From:* users-boun...@lists.ironpython.com [mailto: > users-boun...@lists.ironpython.com] *On Behalf Of *Justin Chase > *Sent:* Wednesday, April 14, 2010 11:24 AM > > > *To:* Discussion of IronPython > *Subject:* Re: [IronPython] Building via AST > > > > I feel like I'm sooooo close but something isn't quite working. Here is my > current code: > > > > var runtime = Python.CreateRuntime(); > > > runtime.LoadAssembly(typeof(IExample).Assembly); > > > > var engine = > runtime.GetEngineByFileExtension(".py"); > > var context = > (PythonContext)HostingHelpers.GetLanguageContext(engine); > > > > var globals = new PythonDictionary(); > > globals.Add("__name__", "<test>"); // I > get an exception without this. > > > > var options = new > PythonCompilerOptions(ModuleOptions.ExecOrEvalCode | > ModuleOptions.Initialize); > > var unit = new SourceUnit(context, > NullTextContentProvider.Null, "", SourceCodeKind.Statements); > > > > var moduleContext = new > ModuleContext(globals, context); > > var codeContext = new CodeContext( > > new PythonDictionary(), > > moduleContext); > > > > var classDefinition = new > IronPython.Compiler.Ast.ClassDefinition( > > "Example", > > new Expression[] { }, > > new FunctionDefinition( > > "Do", > > new[] { new > Parameter("self") }, > > new > ReturnStatement(new ConstantExpression("hello python!")))); > > > > var pythonAst = new PythonAst( > > new > IronPython.Compiler.Ast.SuiteStatement(new Statement[] { /* import, */ > classDefinition }), > > false, > > ModuleOptions.ExecOrEvalCode, > > false, > > new CompilerContext( > > unit, > > options, > > new > ThrowsErrorSink())); > > > > pythonAst.Bind(); > > var lambda = > (System.Linq.Expressions.LambdaExpression)pythonAst.Reduce(); > > var func = (Func<CodeContext, > FunctionCode, object>)lambda.Compile(); > > var result = func(codeContext, null); // > result is null > > > > dynamic python = > HostingHelpers.CreateScriptScope(engine, moduleContext.GlobalScope); > > *dynamic example = python.Example(); // > fails! Example is not in scope.* > > Console.WriteLine(example.Do()); > > Console.ReadKey(true); > > > > > > Can anyone tell me what I'm missing? This has got to be pretty close. > > > > > > On Mon, Apr 12, 2010 at 7:51 PM, Justin Chase <justin.m.ch...@gmail.com> > wrote: > > Awesome. I will thanks. > > On Apr 12, 2010 7:49 PM, "Dino Viehland" <di...@microsoft.com> wrote: > > 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! J > > > > *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 t... > > > _______________________________________________ > Users mailing list > 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 > > > > > -- > Justin Chase > http://www.justnbusiness.com > > _______________________________________________ > Users mailing list > 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