Great! Thanks Dino. With the following C# code:
using System; using System.Collections; using System.Collections.Generic; using IronPython.Compiler.Ast; using Microsoft.Scripting; namespace ExpressionWalker { public class ExpressionWalker : PythonWalker { public List<string> names = new List<string>(); public override bool Walk(NameExpression node) { names.Add(SymbolTable.IdToString(node.Name)); return true; // means walk this node, not important for a Name node. } } } The following Python code: import clr clr.AddReference('ExpressionWalker') clr.AddReference('IronPython') clr.AddReference('Microsoft.Scripting') from IronPython import PythonEngineOptions from IronPython.Hosting import PythonEngine from IronPython.Compiler import Parser from Microsoft.Scripting import CompilerContext, SourceCodeUnit from ExpressionWalker import ExpressionWalker expression = "A1 * 3 + B4" pe = PythonEngine.CurrentEngine s = SourceCodeUnit(pe, expression) c = CompilerContext(s) p = Parser.CreateParser(c, PythonEngineOptions()) e = p.ParseExpression() w = ExpressionWalker() e.Walk(w) print list(w.names) Produces: ['A1', 'B4'] This works in Silverlight (which is my intention). :-) I'll add this to the cookbook, but I realise that parts of this interface may be unstable... Michael Dino Viehland wrote: > PythonWalker and MS.Ast.Walker are actually different - PythonWalker walks > the IronPython AST before its transformed to a DLR AST, and MS.Ast.Walker > walks the DLR AST. > > You can certainly party on the Expression object all you want. But it'd be > much easier (and less prone to break as we make changes to the AST) to create > a subclass of PythonWalker. This is really easy in C# because it's just: > > class MyWalker : PythonWalker { > public override bool Walk(NameExpression node) { > Console.WriteLine(SymbolTable.IdToString(node.Name)); > return true; // means walk this node, not important for a > Name node. > } > } > > Then: > e = p.ParseExpression() > e.Walk(MyWalker()) > > >From Python it's a little more tricky because all the Walk nodes are > >overloaded - and by a little more tricky I mean you just need to test the > >type of node coming in :). > (I haven't actually compiled any of this, but that's the theory). > > > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Michael Foord > Sent: Monday, August 13, 2007 5:06 PM > To: Discussion of IronPython > Subject: Re: [IronPython] Dear Lazy Web - IronPython 2 Parser > > Thanks for the reply Dino. > > Leaving some kind of API exposed to the Python parser would be > appreciated, rather than making it private. > > What I would like to do in this case, is discover what variable names a > Python expression uses. > > I know how to do this for a Python AST (name nodes that are the first > child of an atom node). I don't even need to modify the AST - I just > want to pull the names out. > > From what you said, I *think* that using Parser.CreateParser sounds the > closest. > > With the help you provided, I got as far as the following code: > > import clr > clr.AddReference('IronPython') > clr.AddReference('Microsoft.Scripting') > > from IronPython import PythonEngineOptions > from IronPython.Hosting import PythonEngine > from IronPython.Compiler import Parser > from Microsoft.Scripting import CompilerContext, SourceCodeUnit > > expression = "3 * 3" > pe = PythonEngine.CurrentEngine > > s = SourceCodeUnit(pe, expression) > c = CompilerContext(s) > p = Parser.CreateParser(c, PythonEngineOptions()) > > e = p.ParseExpression() > > This gets me a BinaryExpression object, which has interesting properties > like 'Left', 'Right', 'Start' and 'End' and a Walk method that takes a > PythonWalker. (Presumably BinaryExpression is a node type - the root > node of this particular expression.) > > I can find Microsoft.Scripting.Ast.Walker (which has multiple overloads > of Walk for different node types). I assume the PythonWalker is a > subclass of this. > > Can I use the expression object to inspect its nodes without creating a > walker? > > Thanks for the help. :-) > > Michael > > Dino Viehland wrote: > >> I don't know if you figured this out yet but here goes... >> >> Our Parser class is still public (I'm not sure if this will change or not) >> but you can do (IronPython.Compiler.)Parser.CreateParser. That takes a >> CompilerContext class which is going to point the parser at a SourceUnit >> that we are currently parsing. >> >> >From there you can call ParseFileInput and it'll parse the file and return >> >you the IronPython AST. The interesting part might be if you actually want >> >to compile that code later on :). In that case you might want to look at >> >PythonScriptCompiler to see the rest of the process - it's really just one >> >call to PythonScriptCompiler.BindAndTransform which also seems to be public >> >(again, I'm not sure if that'll change or not). >> >> Alternately if you just want a way to paramterize some user code you might >> want to look at ScriptCompiler.ParseCodeDom. This allows you to provide a >> limited CodeDom tree (we support CodeMemberMethod, and snippet statement / >> expressions and that's it) which you could create from some user input. The >> nice thing about that is it won't be Python specific (although I'm guessing >> that's not a problem for you :) ). >> >> >> -----Original Message----- >> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Michael Foord >> Sent: Wednesday, August 08, 2007 3:50 PM >> To: Discussion of IronPython >> Subject: [IronPython] Dear Lazy Web - IronPython 2 Parser >> >> Hello all, >> >> Sorry for being lazy, but... >> >> What is the easiest way of building an AST from IronPython 2 code? I >> would like an AST that I can modify and then flatten again in >> Silverlight.... It needn't be a Python AST, an IronPython one is fine. I >> only need access to 'name' nodes... I wish to change some of the names >> and turn the AST back into code before exec'ing. >> >> :-) >> >> Thanks >> >> >> Michael >> http://www.ironpython.info/ >> _______________________________________________ >> Users mailing list >> Users@lists.ironpython.com >> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com >> _______________________________________________ >> Users mailing list >> Users@lists.ironpython.com >> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com >> >> >> >> > > > _______________________________________________ > Users mailing list > Users@lists.ironpython.com > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com > _______________________________________________ > Users mailing list > Users@lists.ironpython.com > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com > > > _______________________________________________ Users mailing list Users@lists.ironpython.com http://lists.ironpython.com/listinfo.cgi/users-ironpython.com