.dfmをYAMLのように使う

Delphiでは、RTTIを用いたストリーミングで、.dfm形式については比較的簡単に読み書きすることができます。.dfmの実体はWindowsのリソースファイルですので、実行ファイルにリンクすることもでき、実際にVCLでは、フォームエディタで設計時に配置したコンポーネント群をリソースとして、実行時に復元することでRADを実現しています。
Delphi限定ですが、.dfmというのは便利なフォーマットですので、汎用のデータファイルとしても色々使いたいのです。
汎用のデータファイルについてはXMLYAMLJSON等がありますが、これらはそれぞれに長所と短所があります。主に好みのレベルで。私はこの中ではYAMLが好きです。
そこで、.dfmとYAMLの間の対応表を作って幸せになろうとそんな話です。
.dfmはバイナリフォーマットですが、幸いテキストでの表現も用意されており、以下ではテキストでの表現を使用しています。DelphiIDEで開く/付属のconvert.exeで変換する/その辺に転がってるツールを使う、等でテキスト表現を見ることができます。
map (outside)

--- !TypeName
...
object TypeName
  ...
end

YAMLとしてはlistとmapのどちらからでも開始できますが、.dfm形式からくる制約により最外周は必ずmapになります。

map

--- !TypeName
A: 1
B: 3.14
C: "string"
D: SYMBOL
...
object TypeName
  A = 1
  B = 3.14
  C = 'string'
  D = SYMBOL
  ...
end

各型のプロパティとして対応付けます。

map (in map)

--- !TypeName
E:
 A: 1
 B: 3.14
 ...
...
object TypeName
  E.A = 1
  E.B = 3.14
  E. ...
  ...
end

TPersistent派生のプロパティとして表現できますが、やや冗長です。

--- !TypeName
&E E: !TypeOfE
 A: 1
 B: 3.14
 ...
...
object TypeName
  object E: TypeOfE
    A = 1
    B = 3.14
    ...
  end
  ...
end

TComponent派生のプロパティとしても表現できますが、型名が必要となりますし、アンカーとしても機能してしまうため名前が重複できなくなります。逆に言えばmap以外はアンカーを付けられません。

どうでもいいですがYAMLのReference Parser、タグとアンカーが続く場合をパースできないような……。
↓エラーになる。

--- !TypeName
&E E: !TypeOfE
 A: 1
 B: 3.14

↓パースできる。

--- !TypeName
E: !TypeOfE
 A: 1
 B: 3.14
---
&E E: !TypeOfE
 A: 1
 B: 3.14
--- !TypeName
A: 1
&E E: !TypeOfE
 A: 1
 B: 3.14

list

--- !TypeName
F:
 - 1
 - 3.14
 ...
...
object TypeName
  F = (1 3.14 ...)
  ...
end

スカラー値のlistは、.dfmでもリスト(vaList)として表現します。直接対応するPascalの型はありませんので、読み書きのためにはDefinePropertiesをoverrideする必要があります。場合によっては集合型も使えます(括弧が[ ]になります)。

map (in list)

--- !TypeName
G:
 -
  A: 1
  B: 3.14
  ...
 -
  A: 2
  B: 1.41
  ...
 ...
...
object TypeName
  G = <
    item
      A = 1
      B = 3.14
      ...
    end
    item
      A = 2
      B = 1.41
      ...
    end
    ...>
  ...
end

mapのlistは、TCollection派生のプロパティとして表現します。

list (in list)

--- !TypeName
H:
 -
  - 1
  - 3.14
  ...
 -
  - 2
  - 1.41
  ...
 ...
...
object TypeName
  G = ((1 3.14 ...) (2 1.41 ...) ...)
  ...
end

Pascalの型として集合の集合はありませんが、.dfmの表現上は可能です。読み書きはDefinePropertiesをoverrideする必要があります。

map (in list in list)

--- !TypeName
I:
 -
  -
   A: 1
   B: 3.14
   ...
  -
   A: 2
   B: 1.41
   ...
  ...
 -
  -
   A: 3
   B: 1.73
   ...
  ...
 ...
...
object TypeName
  I = (
    <
      item
        A = 1
        B = 3.14
        ...
      end
      item
        A = 2
        B = 1.41
        ...
      end
      ...>
    <
      item
        A = 3
        B = 1.73
        ...
      end
      ...>
    ...)
  ...
end

TCollection派生の更に集合として表現します。

まとめ

YAML .dfm
list (of map) TCollection
list set
map (in map) TPersistent / TComponent
map (in list) TCollectionItem
map (outside) TComponent