※読む価値無しのメモ書き。以下記事の内容の追記と修正。読んでも意味が分からないだろうし性質として妄言。

◆ペイロードじゃなくてフィールド

「>」でペイロードの開始。

ペイロードっていうかフィールドの開始だわな。言葉がおかしい。型の定義にも使うからペイロードじゃない。

「>」はデリミタ(区切り文字)であることだなぁと思った。オブジェクトの内部を区切るデリミタ。かたやフィールドの内部を区切るデリミタもある。「$」とか「:」とか

「{}」とか「<>」はエンクロージャだろうか。いちいちそう呼ばないけど。

◆メタデータにアクセス出来ていいわけない

「?」でメタデータにアクセスできるって話だった。

%env:{
  >target:"staging"
  >port:8080
}
%endpoint:"https://example.com/api"

>hoge:{
  >target: ?env.target
}

が、そんなこと出来ていい訳がない。ただ、文字を繰り返し読みたいという需要はある。メタデータはペイロードから参照できてはならんので、ラベルという名前で定義するのが良いと思った。

▼ラベル

「#」始まりだろか。ASCII記号の枯渇が怖い。意味が合ってるわけでもないし。

#env:{
  >target:"staging"
  >port:8080
}
#endpoint:"https://example.com/api"

>hoge:{
  >target: ?env.target
}

ペイロードから参照可能なのはラベルだけで、同名のラベルが1ファイルに複数定義されていたら書式エラー。後勝ちにはならない。

ペイロードからペイロードの参照は出来ない。無理。ラベルからラベルの参照は可能だが、先で定義されたラベルだけ参照可能。ペイロードからラベルを読むのも、先にラベルが定義されていないと不能。そうしないと機械的な解釈がキツい。

ユーザー定義ラベルは小文字始まり。組み込みラベルがあるかどうかは知らない。

◆文字列埋め込み

例えばstrというラベルから文字を読むときは以下でいける。

#str:"cd"
>hoge:"ab"?str"efg"

hogeは「abcdefg」を意味できる。

フィールドの値として文字列をいくつ並べても問題がない。単に連結すればいい。+等の記号でつなぐ必要なし。間にスペースがあろうが改行があろうが無視。ただ誤解の余地があるかも。

>hoge:"aa""bb"

これ「aa”bb」ならぬ「aabb」になる。この例の””は”のエスケープじゃないから。文字列をふたつ並べてるから一つの文字列として解釈される。

これは文字をストリームで書き込むときにエスケープが有利。「#””#」囲みで「”」のエスケープが不要になるんだけど、「”#」という文字列が出現した時はエスケープが必要になる。文字列をストリーム処理していく中で「”#」を発見したときはそこで切り替えて緊急脱出できる

>hoge:#"abc""# "#" #""def"#

なんだか呪文みたいだけど、これは「abc”#”def」を表現できる。そして空白は除去できる。

>hoge:#"abc""#"#"#""def"#

読めません><。でもまぁエッジケースだから何でもいいんだ。「##””##」で囲めば「”#」をエスケープする必要もない。その代わり「”##」のエスケープは必要になるけど。

>hoge:##"abc"#"def"##

◆行コメントアウト無理

//行コメントは「//」で開始してCRかLFで閉じる。

これ無理。CRもLFもコメントアウトのためだけに区切り文字として扱うことはできない。改行文字に意味は持たせられない。内容を「””」とか「#””#」で囲めよ。仕方がねぇよ。

◆配列の区切り

色々考えた結果として、配列の各要素の区切りは「;」にしたかった。「,」じゃなくしたい。オブジェクトの配列を以下の書きっぷりにしたい。以下の例のBookはtitle、price、authorの3プロパティを持つ。

あと配列はユーザー定義じゃないからPascalCaseじゃなくてcamelCaseになる。array。ユーザー定義はPascalCaseのみ許可。

>@array<Book>:[
  "星の王子様",1500,"アントワーヌ・マリー・ジャン=バティスト・ロジェ・ド・サン=テグジュペリ";
  "ウォッチメン",3740,"アラン・ムーア&デイブ・ギボンズ";
  "ねないこだれだ",770,"せなけいこ";
]

引き換えとして、配列がこんな書き方になる。

>numArray:[
  1;
  2;
  3;
]
>strArray:["aaa";"bbb";"ccc";]

まぁ分からんでもない。JSONに無理に合わせることもない。カンマ区切りでオブジェクトを記述できたほうがCSVからしてわかりやすい。

◆KeyValueとTuple

KeyValue必要でTuple要らないとか書いたけど、どちらかと言えばTupleこそ必要だと思った。数値のインデックスでアクセス可能な固定長の組。

改めてなにゆえtupleが必要なのかと言えば、JSONからsenに変換するためにkeyValueが必要だから。JSONはフィールド名に空文字とかスペースとか数字始まりとか記号とか許可しちゃっている。

{
  "":"",
  "?":"",
  " ":"",
  "123":""
}

デシリアライズしづら過ぎて相互運用性がバリ低いのでsenはそういうフィールド名を許可しない。だからJSONからの変換にはkeyValue型が必要。そのkeyValueはtupleのサブクラスっていうかバリエーションとして考えたい。

/"100円のリンゴ"
>@tuple<string,number>:("apple",100)
/"tupleのフィールドに命名"
>@tuple<string$fluitName,number$price>:("apple",100)

ジェネリクスの型指定「<>」の内側に記述される型は「@」を省略できる。省略しなくても良い。ただし記述順序を入れ替えたい場合は必須で「@」を書く。

/"tupleのフィールドに命名"
>@tuple<$fluitName@string,$price@number>:("apple",100)
/"tupleの配列"
>@array<tuple<$fluitName@string,$price@number>>:[("apple",100);("grape",200);("orange",300)]
/"keyという属性の指定。属性の記法が変わったのは後述。"
>@array<tuple<$fluitName@string!+key,$price@number>>:[("apple",100);("grape",200);("orange",300)]

ほんで、配列内のトップレベルのtupleはパーレンの省略を許可する。

/"keyという属性の指定。"
>@array<tuple<$fluitName@string!+key,$price@number>>:["apple",100;"grape",200;"orange",300]

これはオブジェクトの配列の書き方と同じ。

*Fruit:{
  >name@string
  >price@number
}

>@array<Fruit>:["apple",100;"grape",200;"orange",300]

つまるところ、オブジェクト定義に順序まで一致するtupleで対象のオブジェクトをコンストラクトできる。等価。

この例で言えば一番外側の「[]」を「{}」にして「,」を「:」にして「;」を「,」にすればJSONになる。tuple内のtupleはパーレンをブレースにしたればよい。

(型の指定が無かったとしても)配列におけるtupleの要素数は固定長にしたい。固定長に出来ないんならデータ設計が間違ってます。多次元配列の要素数は可変長。

◆ルートチェンジ

ファイルのある位置で「|」と「=」を記述することにより、それ以降の記述内容の階層を変更する。

どういう意味かわからんわ。

そもそも、senファイルのトップレベルは無名のオブジェクトになっている。そのトップレベルオブジェクトの階層を一度だけ変更できる。下の階層にドリれる。

便宜上「senファイル」と言っているが、別にKVSのVに突っ込むテキストでも問題ない。

以下は無名のBook配列に変更した例。無名が嫌なら$で名前つけてもよい。

|@array<Book>=
"星の王子様",1500,"アントワーヌ・マリー・ジャン=バティスト・ロジェ・ド・サン=テグジュペリ";
"ウォッチメン",3740,"アラン・ムーア&デイブ・ギボンズ";
"ねないこだれだ",770,"せなけいこ";

「=」とか「;」の後に改行を入れてるけど、入れる必要ない。入れても無視される。

なんでそんな書き方が必要なのかって、配列をストリーム処理したいから。入力されたレコードをファイルの末尾に追加して済ませたい。エロ同人CSVみたいに!

以下は名前付きの別のオブジェクトに変更した例。用途が考え付かない。トップレベルに書くのとそう変わらん気がしている。いや、型指定できるから用途はあるのか。

|$hoge@Book=
>title:"星の王子様"
>price:1500
>author:"アントワーヌ・マリー・ジャン=バティスト・ロジェ・ド・サン=テグジュペリ"
>price:1600

オブジェクトの同じプロパティに二度値を設定した場合は後勝ち。上から読まれていったとき、priceフィールドは1600で解釈される。テキストファイルの末尾に「>price: 880」を追記してPATCHできる。変更記録を残せる。

「|=」にはプリミティブ型、つまりstringやらnumberも指定可能。「;」で区切って値を追加すれば更新できる。

あと、ルートチェンジ時にだけ指定できるbinaryという特殊型が有り得ると思った。

|$picture@binary=

上記の例ではpictureというフィールドにbinary型を指定している。「=」以降が急に問答無用でバイナリ。bytelengthなんかは指定不可だろうか。MIMEは指定できたほうがいいだろうか。わからん。

%sen@sen:{
  >author:"田中太郎"
  >name:"猫画像"
  >createdAt:2023-01-01T00:00:00+09:00

}

|$picture@binary=XXXXXXXXXXXXXXXXX

「@sen」はsen共通メタデータの型。

こんな感じだろうか。MIMEはなんらか必要だな。「image/png」とか書いておきたい。バイナリを格納するsen自体の拡張子も変えたほうが良いような気がする。catImage.binsenみたいな。びんせん。あるいはもうcat.png.binsenみたいにしておけばファイルエクスプローラーでサムネイル画像を表示するプラグインとか書けるわ。

あとは画像からスプライトを切り出すためのデータ型とか提供すると捗りそう。1ファイルで色々なことが済む。

▼ルートチェンジ後の動き

  • 追加でルートチェンジすることできない。
  • メタデータを弄ったらルートチェンジした後のオブジェクト/配列のメタデータに適用される。

ルートのメタデータに「~」でアクセスすることも考えられる。例えば論理削除のメタデータフィールドを上書きするなら以下。

~%sen.deleted:true

有り得なくはない。「~」はオブジェクト内のデリミタ。いや、そうなると「%」もオブジェクト内のデリミタだから変だな。「%~」って書き方のほうが適切か。

%~sen.deleted:true

うん。

◆平行記述データ定義

Bookというデータ定義をしようとした時。

*Book:{
  >title@string
  >price@number
}

これを配列囲み「[]」にしつつ「,」で区切って順同で定義できる。

*Book:[
  $title,$price;
  @string,@number;
]

この書き方の何が嬉しいのという感じだけど、列のクソ多いデータを定義するときにエディタから多少見やすくできるかも。パースにも無理がない。でも意味があるのか良くわからない。表をピボットできるということに一人で感心してたってだけ。

ただ、属性を「!」開始で設定しようと思ったときに無理になるかも。ひとつのフィールドに複数の属性を付けられなくなる。それゆえ「属性の記述開始」と「属性の設定」は別の記号を割り振らねばならんかった。

で、属性そのものの記述開始を「+」あるいは「-」にしたい。属性の設定開始は「!」。

*Book:[
  $title,$price,$isbn;
  @string,@number,@string;
  ,,!+deprecated;
]

「+」「-」が何かって、属性の追加と打ち消しを意味している。なんで属性の打ち消しが必要なのかといえば、属性も後勝ちだから。消したくなったら「-」を追記して消せばいい。

◆ルートチェンジ型定義

|*Book=
>title:string
>price:number
>author:string

こんなん。

priceフィールドにdeprecated属性を付与して、除去する例。

|*Book=
>title:string
>price:number
>author:string
>price!+deprecated
>price!-deprecated

RDBのカラムみたいに項目名を変更できるようにしたいんなら不変のIDが必要になるだろう。=とか使えばいいんかな。記号被りが気になるけども。

◆タイムスタンプ

「^」で。キャレット以外の記号がもうない。クォートくらい。

>title: "ねないこだれだ"
>price: 770
>isbn: "978-4834002188"
>price: 880 ^2023-10-18T12:00:00+09:00

priceを書き換えたのは2023年10月18日12時(日本時間)。

git等で管理すりゃええやん説もある。文字数が膨らむし。嘘っこのタイムスタンプ手書きされても面倒かもな。とはいえ編集時刻を埋め込めるのは結構つよい。トランザクション処理周りに噛ませられる。オペレーションID的なものも欲しくなるな。とりあえず考えないけども。

「^」は「%~sen.updatedAt:」のショートハンド。トップレベルのsen標準メタデータに於けるupdatedAtフィールドを上書きする。

省略しない書き方は以下。

>title: "ねないこだれだ"
>price: 770
>isbn: "978-4834002188"
>price: 880 %~sen.updatedAt:2023-10-18T12:00:00+09:00

ながい。

更新者情報とかも持たせたいんなら、「^updateAt:2023-10-18T12:00:00+09:00」くらいのショートハンドに収めておいた方がいいのかも?

◆リファレンス

sen間の参照について考えて書きたいけどもう無理。時間かかりすぎる。

他のファイルから型とかラベルとか参照するような書き方について。

絶対パスと相対パス。インターネットまたげる。httpとか。

記法については考えてないけどJavaScriptのモジュールのインポートは何となく有り得る書き方な気がしている。エイリアスとかも考えたいいけど「as」とかってキーワードは使えないのでつらい。

import { hoge } from "https://example.com/hoge.d.sen"

◆結

しらん。ある程度仕上げたらパーサー書こうかなとか考えてたけど考えすぎて飽きた。疲れた。また今度。

  • メモ:日付、日時、時刻まわりをシングルコーテーションで囲めばいいかなと思った。
  • メモ:圧縮との相性を見たい。gz圧縮したレコードやらフィールドをケツに接続すりゃ追記が成るはず。圧縮したままの持ちまわしがどれくらい効くんだか知りたい。eStargzも検討。
  • メモ:文字列中の改行はエスケープできたほうがいい場合有り得るなと思った。CSVで1行1レコードで扱いたいときに改行がエスケープできなくて困った記憶ある。