2016/12/12
PowerShellのAST入門
この記事はPowerShell Advent Calendar 2016の11日目です。遅刻してごめんなさい!
ASTとは
ASTとはAbstract Syntax Treeの略で、日本語では「抽象構文木」といいます。コードをパーサーが構文解析した結果から、言語の意味に関係のない要素(空白等)を除外し、木構造として構築したものです。
PowerShellでは3.0からASTの仕組みが取り入れられました。スクリプト実行時にはまずパーサーがスクリプトブロックからASTを生成し、コンパイラによってASTが解釈され、実行されるようになっています。
ASTを直接的に扱うのはコンパイラですが、実はPowerShellではパーサーが構築したASTを、PowerShellスクリプトから扱うことができます。
ASTの具体的な使い道としては、構文の静的解析が挙げられますが、その話は後でするとして、今回はまず、ASTの構成要素と構造を見ていきます。
ASTの構成要素
具体的には、{スクリプトブロック}.Astとして、ScriptblockオブジェクトのAstプロパティから、ScriptBlockAstオブジェクトにアクセスできます。このオブジェクトがASTのルートとなるノード(分岐点)を表します。このScriptBlockAstから、スクリプトブロック内部の構文要素が木構造として展開されていきます。
式(Expression)、文(Statement)といった構文要素は、各々対応したAstクラスが対応し、木構造における分岐点を形成します。また、分岐点の末端の葉では、当該の構文要素を構成するデータを示すオブジェクトが格納されます。
すべてのAstクラスは、Ast抽象クラス(System.Management.Automation.Language.Ast)を継承したクラスです。PowerShellでは50個程のAstクラスが存在します。各Astクラスは、抽象クラスで定義されている以下の2つのプロパティを持っています。
- Parent
親ノードを示すAstオブジェクトを返す - Extent
当該のASTノードに含まれるコード文字列や、スクリプト全体から見たコード文字列の位置等の情報を持つ、IScriptExtentインターフェースを実装したクラスのオブジェクトを返す
また各Astクラスは、対象の構文要素に応じて、それぞれ異なったプロパティを持ちます。たとえばScriptBlockAstは以下のプロパティを持ちます。
子の分岐点を返すもの
- UsingStatements
Using節を表す、UsingStatementAstのコレクションを返す - Attributes
スクリプトブロックに付与された属性を表す、AttributeAstのコレクションを返す - ParamBlock
paramブロックを表す、ParamBlockAstを返す - BeginBlock、ProcessBlock、EndBlock、DynamicParamBlock
各々、beginブロック、processブロック、endブロック、DynamicParamブロックを示すNamedBlockAstを返す
葉を返すもの
- ScriptRequirements
#Requires節の内容を表す、ScriptRequirementsを返す
ASTの構造
たとえば、
$scriptBlock = { param([int]$x,[int]$y) end { $out = $x + $y $out | Write-Host -ForegroundColor Red } }
という、二つの整数値の和を赤字で表示するというスクリプトブロックならば、以下のようなASTが構築されます。(一部分岐点、葉は省略しています。また、分岐点のASTクラス名は、末尾の"Ast"を省略表記しています。)
このスクリプトブロックのASTから、例えば「Red」というパラメータ値を表す、StringConstantExpressionAstまで辿るには、
$scriptBlock.Ast.EndBlock.Statements[1].PipelineElements[1].CommandElements[2]
StringConstantType : BareWord Value : Red StaticType : System.String Extent : Red Parent : Write-Host -ForegroundColor Red
のようにします。
基本的なASTの構造が頭に入っていれば、タブ補完を併用することで比較的簡単に目的のノードまで辿れますが、ASTノードの子に対し、ノード検索をかける方法もあります。
例えば、すべてのVariableExpressionAstを列挙するには、
$scriptBlock.Ast.FindAll({ param($ast) $ast -is [System.Management.Automation.Language.VariableExpressionAst] }, $true)
のように、FindAllメソッドを用います。
AST編はあと何回か続く予定です。
2016/07/11
CLR/H #clrh101「PowerShell の概要と 5.x 新機能のご紹介」資料公開
大変遅くなってすみません。7/2(土)、札幌で開催されたCLR/H #clrh101で行ったセッション、「PowerShell の概要と 5.x 新機能のご紹介」の資料を公開します。
札幌は涼しくて、何もかも美味しくて良かったです。夏の関西は人間の生存に適した気候とはとても言えないので、しばらく札幌に滞在していたかったですね。
さて、登録ページでのタイトルと若干違いますが、間もなく(8/2に)Windows 10 Anniversary Updateの登場とともにPowerShell 5.1の正式版が利用できるようになるということで、今回、5.0に加えて5.1の新機能もご紹介することにしたためです。(スライドは5.1の新機能の部分以外は、基本的にこれまでの内容と同様です。ご容赦ください。)
なお、PowerShell 5.1は現在のところ、Windows 10 Insider PreviewかWindows Server 2016 TP5で試すことができます。
PowerShell 5.0の登場からWindows Server 2016正式リリースまでの期間がけっこう空いたことと、ラピッドリリースの方針もあって、5.1が短期間で登場することとなりました。なのでどれが5.0でどれが5.1の機能かというのは割と曖昧ですけど、5.1で一番大きく変化するところは、PowerShellのエディションがDesktop EditionとCore Editionに分かれるところだと思います。
PowerShell Core Editionは従来のPowerShellのサブセット版となり、Windows Server 2016のインストールオプションの一つで、フットプリントを軽量化し、Windowsコンテナ技術に最適化された、Nano Serverで動作させることを目的として作られました。
Core Editionでは一部のコマンドレットのみのサポートとなりますが、基本的にNano Serverの管理はリモート経由でPowerShellを直接的あるいは間接的に用いて行うことになるため、当然ながら必須のコンポーネントとなります。
なお、PowerShell Core Editionは先日、1.0リリースを迎えたばかりの、.NET Core上で動作します。.NET Coreとは.NET Frameworkのサブセットで、マルチプラットフォームで動作し、OSSとして開発されています。
.NET Framework上で動作する、従来のフルセット版PowerShellも、Desktop Editionとしてこれまで通り利用可能です。
PowerShell 5.0、5.1の新機能はMSDNでまとめられているのでそちらもご参照ください。
Windows 管理フレームワーク (WMF) 5.0 RTM のリリース ノート概要 | MSDN
WMF 5.1 Release Notes (Preview)
追伸。Microsoft MVP for Cloud and Datacenter Managementを7月付で再受賞いたしました。おかげで今回のイベントで「関西MVP3人が集結」という触れ込みが嘘にならなくて良かったです。そして同じ分野でCLR/Hのスタッフでもある素敵なおひげさんも受賞されました。おめでとうございます。
Copyright © 2005-2018 Daisuke Mutaguchi All rights reserved
mailto: mutaguchi at roy.hi-ho.ne.jp
プライバシーポリシー