分析IronPython中的代码链

本文关键字:代码 IronPython 分析 | 更新日期: 2023-09-27 18:14:21

ironpython中是否有帮助分析python代码的方法?

例如下面这个脚本

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)

我需要知道filters.delta如何在脚本中调用,如bar(x)> foo(b)> filters.delta(f)

这可以从IronPython完成还是我需要自己解析脚本?这不是很容易做到的

<<p> 背景信息/strong>

这个软件叫做FreePIE。它是一个可编写脚本的输入输出模拟器。它有一组util函数。考虑以下代码:

mouse.deltaX = filters.delta(joystick[0].x)

它获取操纵杆或手柄的绝对x坐标,使用filers.delta获得delta值并设置鼠标的相对x坐标

为了得到delta值,我的软件必须在脚本执行之间比较两个样本,util函数负责这个。

[NeedIndexer]
public double delta(double x, string indexer)
{
    var lastSample = x;
    if (deltaLastSamples.ContainsKey(indexer))
        lastSample = deltaLastSamples[indexer];
    deltaLastSamples[indexer] = x;
    return x - lastSample;
}

但是为了解决这个问题,它需要存储最后一个样本。正如您所看到的,它接受一个字符串,该字符串可以索引包含最后一个示例的集合。为了简单,我不想要求用户处理这个索引。所以我所做的是准备脚本,并寻找具有[NeedIndexer]属性的所有方法。如果我找到一个,我会解析方法参数并将其用作索引器。因此,像上面这样的python脚本在解析

之后看起来像这样
mouse.deltaX = filters.delta(joystick[0].x, "joystick[0].x")

在这个例子中,代码将工作,因为joystick[0].x是唯一的,但是如果用户定义一个python函数并从那里使用filters.delta,他将索引所有样本的相同变量名。

解析脚本的当前代码https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.Core/ScriptEngine/Python/PythonScriptParser.cs L135

我希望我能说清楚我想要达到的目标

多亏了Jeff的回答,我才有了更进一步的了解

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);

我已经能够使用ast.dump将整个树转储为字符串,但我还没有发现如何递归地迭代树。我需要这样做,直到我找到一个filters.delta调用,然后再次遍历备份并向链中的每个函数添加一个参数。网上没有太多关于最后一个模块的信息。有人知道这是怎么实现的吗?对象上有一个_fields成员它是由ast.parse返回的但是我找不到从那里去

分析IronPython中的代码链

首先,我认为你应该重新考虑你是怎么做的。任何解决方案都将是脆弱和神奇的,并且可能在未来的道路上造成更多的问题。像mouse.deltaX = joystick[0].x_filters.delta()这样的东西会更清楚。你甚至可以动态地创建x_filters(它不一定是操纵杆类型的一部分),方法是用DynamicObject包装器包装操纵杆,根据需要创建x_filters

如果你想修改脚本,你可能想使用ast模块来解析代码。你仍然需要走最后一圈来寻找那个函数。是否处理绑定到不同名称的函数等取决于您。最后一个模块也应该为您提供符号的文本位置,以便您可以在其后面插入特殊代码。

你也可以在运行时使用sys。settrace,如果你在创建引擎时启用"Tracing"选项,它应该在IronPython下工作。但这可能对您的目的来说太晚了。