PowerShell AST修改和范围

chr*_*chu 5 powershell abstract-syntax-tree extent

我目前正在尝试使用PowerShell 3.0中引入的AST功能来修改ScriptBlock.我的要求是ScriptBlock的参数块中的所有参数都获得一个[Parameter(Mandatory)]属性.

基本上代码应该修改这个:

Param([string]$x)

Write-Host $x
Run Code Online (Sandbox Code Playgroud)

对此:

Param([Parameter(Mandatory)][string]$x)

Write-Host $x
Run Code Online (Sandbox Code Playgroud)

但是,我在添加新属性时遇到了一个问题,因为它需要一个IScriptExtent,我不知道应该如何创建一个新属性IScriptExtent.

如何创建新的脚本范围?我可以使用什么价值的头寸?我是否必须更改所有后续范围的位置?

我尝试重用我正在修改的每个参数的范围,但不幸的是,这似乎没有产生它应该的结果(例如,当我调用ToString修改后ScriptBlock我没有看到任何变化).

到目前为止,我的实现基于此处ICustomAstVisitor发现.

最重要的方法如下:

public object VisitParameter(ParameterAst parameterAst)
{
   var newName = VisitElement(parameterAst.Name);

   var extent = // What to do here?

   var mandatoryArg = new AttributeAst(extent, new ReflectionTypeName(typeof (ParameterAttribute)),
        new ExpressionAst[0],
        new[] {new NamedAttributeArgumentAst(extent, "Mandatory", new ConstantExpressionAst(extent, true), true)});

   var newAttributes = new[] {mandatoryArg}.Concat(VisitElements(parameterAst.Attributes));
   var newDefaultValue = VisitElement(parameterAst.DefaultValue);
      return new ParameterAst(parameterAst.Extent, newName, newAttributes, newDefaultValue);
}
Run Code Online (Sandbox Code Playgroud)

Jas*_*irk 3

脚本范围主要用于错误报告,但也用于调试(例如,设置行断点)。

一般来说,合成脚本的选项(如您的示例)是:

  • 重用现有的 ast,大概与您要添加的 ast 接近/相关
  • 使用空 ast (基本上创建 ScriptExtent 和 ScriptPosition 的实例,没有文件,空行)
  • 创建一个综合范围,以某种方式帮助调试,也许有一些特殊的内容

在您的示例中,以上任何一个都是合适的。第二种选择是最简单的。第三个选项只是第二个选项的变体,但您可以将内容设置为有用的内容,例如

<#Generated: [Parameter(Mandatory)] #>
Run Code Online (Sandbox Code Playgroud)

  • 那么“漂亮的打印机”就是整个问题:我什至不需要漂​​亮的代码,我只需要在修改 AST 后获取代码,如果不提供“正确”的范围,这似乎不起作用。在某种程度上,似乎使用字符串修改来修改代码会更容易,而不是涉足 AST,这将是相当遗憾的。 (2认同)