web-dev-qa-db-ja.com

Roslyn SyntaxNodesは再利用されますか?

私は Roslyn CTP を調べていますが、これは Expression tree API と同様の問題を解決しますが、どちらも不変ですが、Roslynはまったく異なる方法でこれを行います:

  • Expressionノードには親ノードへの参照がなく、ExpressionVisitorを使用して変更されます。そのため、大きなパーツを再利用できます。

  • 反対側のRoslynのSyntaxNodeには、その親への参照があるため、すべてのノードは事実上、再利用できないブロックになります。 UpdateReplaceNodeなどのメソッドは、変更を行うために提供されています。

これはどこで終わりますか? DocumentProjectISolution? APIは(ボタンを押すのではなく)ツリーの段階的な変更を促進しますが、各ステップは完全なコピーを作成しますか?

なぜ彼らはそのような選択をしたのですか?私が見逃している興味深いトリックはありますか?

121
Olmo

更新:この質問は 2012年6月8日の私のブログの主題 でした。すばらしい質問をありがとう!


すばらしい質問です。私たちはあなたが提起する問題について長い間議論しました。

次の特性を持つデータ構造が必要です。

  • 不変。
  • 木の形。
  • 子ノードから親ノードへの安価なアクセス。
  • ツリー内のノードからテキスト内の文字オフセットにマップできます。
  • 永続的

persistence とは、テキストバッファに対して編集が行われたときに、ツリー内の既存のノードのほとんどを再利用する機能を意味します。ノードは不変なので、それらを再利用するための障壁はありません。これはパフォーマンスのために必要です。キーを押すたびにファイルの膨大な数のウォッジを再解析することはできません。編集の影響を受けたツリーの部分だけを再Lexして再解析する必要があります。

これら5つすべてを1つのデータ構造に入れようとすると、すぐに問題が発生します。

  • そもそもどうやってノードを作るのですか?親と子はどちらもお互いを参照し、不変なので、どちらが最初に構築されますか?
  • その問題をなんとか解決できたとしたら、どうすればそれを永続化できますか?別の親で子ノードを再利用することはできません。これは、新しい親があることを子に伝えることになるためです。しかし、子供は不変です。
  • あなたがその問題を解決できたとしましょう:新しい文字を編集バッファーに挿入すると、すべてのノードの絶対位置が、そのポイント以降の位置にマップされますが変化します。編集を行うとほとんどのノードのスパンが変更される可能性があるため、永続的なデータ構造を作成するのは非常に困難です。

しかし、Roslynチームでは、不可能なことを日常的に行っています。実際には、 two 解析ツリーを保持することで、不可能を実現しています。 「グリーン」ツリーは不変で永続的であり、親参照はなく、「ボトムアップ」で構築され、すべてのノードはその width を追跡しますが、 absoluteは追跡しません位置。編集が発生すると、編集の影響を受けた緑のツリーの部分のみが再構築されます。これは、通常、ツリー内の解析ノードの総数の約O(log n)です。

「赤い」木は不変の facade で、緑の木の周りに構築されます。 「トップダウン」オンデマンドで構築され、すべての編集で破棄されます。親参照は、ツリーを上から下に降りながらオンデマンドで製造することで計算されます。また、下降すると、幅から絶対位置を計算して、絶対位置を作成します。

ユーザーであるあなたには、赤い木しか見えません。緑の木は実装の詳細です。解析ノードの内部状態を覗くと、実際には別のタイプの another 解析ノードへの参照があることがわかります。これが緑のツリーノードです。

ちなみに、これらは「赤/緑の木」と呼ばれます。これらは、設計会議でデータ構造を描画するために使用したホワイトボードマーカーの色でした。色に他の意味はありません。

この戦略の利点は、不変性、永続性、親参照など、これらすべての優れた機能を利用できることです。コストは、このシステムが複雑であり、「赤い」ファサードが大きくなると、大量のメモリを消費する可能性があることです。現在、利益を失うことなくコストを削減できるかどうかを確認するための実験を行っています。

176
Eric Lippert