Are there any helper methods in ironpython to analyze python code?
Given for example this script
def bar(b):
return foo(b)
def foo(f):
return filters.delta(f) #This is a reference added to the scope from C#
x = 1
bar(x)
I need to know how filters.delta
is called in the script like bar(x) > foo(b) > filters.delta(f)
Can this be done from IronPython or do I need to parse the script myself? Its not very easy done
Background info
The software this is for is called FreePIE. Its a scriptable input output emulator. It has a set of util functions. Consider this code.
mouse.deltaX = filters.delta(joystick[0].x)
It takes the absolute x coordinate of a joystick or gamepad, gets the delta value using filers.delta
and sets the relative x coordinate of the mouse
To get the delta value my software must compare two samples between script execution, the util functions takes care of this.
[NeedIndexer]
public double delta(double x, string indexer)
{
var lastSample = x;
if (deltaLastSamples.ContainsKey(indexer))
lastSample = deltaLastSamples[indexer];
deltaLastSamples[indexer] = x;
return x - lastSample;
}
But to solve that it needs to store the last sample. AS you can see it takes a string that can index the collection holding the last sample. I dont want to require the the user to handle this index for simplicity. So what I do is preparsing the script and look for all methods that has the [NeedIndexer]
attribute. If I find one I parse the method argument and use that as indexer. so a python script looking like above will look like this after parsing
mouse.deltaX = filters.delta(joystick[0].x, "joystick[0].x")
In this example the code will work because joystick[0].x
is unique, but if the user defines a python function and uses the filters.delta
from there he will index on the same variable name for all samples.
The current code for parsing the script https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.Core/ScriptEngine/Python/PythonScriptParser.cs#L135
I hope I make this more clear what I am trying to achieve
Update I gotten a little further thanks to Jeff's answer
var engine = IronPython.Hosting.Python.CreateEngine();
var script = @"def foo(y):
return filters.delta(y)
def bar(x):
return foo(x)
bar(-5)
";
var ast = @"import ast
tree = ast.parse(script)
callback(ast.dump(tree))";
var callback = new Action<object>(o =>
{
Console.WriteLine(o);
});
engine.SetSearchPaths(new[] { "pylib" });
var scope = engine.CreateScope();
scope.SetVariable("script", script);
scope.SetVariable("callback", callback);
engine.Execute(ast, scope);
I have been able to dump the entire tree to a string using ast.dump
but I havent found out how I can recursively iterate over the tree. I need to do this until I find a filters.delta
call, then traverse backup again and add a argument to each function in the chain. There isnt much info on the net about the ast module. Anyone here knows how this can be achived? There is a _fields
member on the object that is returned by the ast.parse
but I cant find out of to go from there