近況 2022-04-30

今月の活動 (ミローネ言語 (ドキュメント、ポインタ、Textmate)、Solotterなど)

ミローネ言語

ドキュメントのメンテ

  • 構文のドキュメントを書いた: milone-lang/syntax.md (現時点のもの)
    • どう書けばいいかよく分からなくて、文章がぎこちない
  • README: 他のユーザーのリポジトリをみていて、サンプルコードがみたいのと、まずコンセプトやモチベーションを知りたいことがあるので、そのあたりを意識して再構成している

型引数の構文

  • F# にもある sizeof<'T> プリミティブを導入するためにシンボルに型引数をもたせる構文を実装した
    • 識別子の直後にある < は型引数の始まりで、それ以外は二項演算とみなす、という方法

線形型 → 所有型

  • 「線形」では分かりにくいので「所有権」(ownership)に関連する単語で呼ぶことにした

ポインタ

ポインタ関連の機能を実装した: 現在のポインタ型のドキュメント

ポインタの型:

  • F# には nativeptr<'T> というポインタを表す型があって、ミローネ言語でも使える
    • Cの T * に対応する
  • Cのconst修飾を扱うために __inptr<'T> という別の型も用意した
    • Cの T const * に対応する
  • constをどこにつけるか:
    • Cでは型を const で修飾することができ、const修飾された型へのポインタ型を作ることで、読み取り専用のポインタを表現している
    • 実際のところconst修飾は、その型自身の性質というより、その型を指しているポインタや、その型のオブジェクトが配置されているストレージの属性として働く
    • constであるという属性はポインタのほうにつけておいたほうが自然な気がする (余談: Rustもそうしている)
  • const vs. in:
    • 前述の通り T const * は読み取り専用のポインタであって定数(constant)へのポインタというわけではない
    • 他の場所にある T * を経由して参照先の値が書き換えられることはありうる
    • C言語にはしばしば構文の流用がみられて、constのこの用法もその一種な気がする
    • 一方 C# では出力引数を表すためにoutキーワードというのがあり、これは事実上書き込み専用の参照として振る舞う
    • その後読み込み専用の参照であるinキーワードが追加された
    • F# では引数が参照であることを型で表していて、inref<'T>, outref<'T>, byref<'T> がある
    • __inptr<'T> などの型名はそこからきている
  • inの逆に書き込み専用のポインタ型 __outptr<'T> も追加した
    • Cではnativeptrと同じく T * に対応する
    • 初期化されていないストレージや出力引数を表すのに使う
    • Rustでは std::mem::MaybeUninit<T> という型を使って未初期化のオブジェクトをラップし、それへの参照を持つことになっている
    • どっちがいいか迷った
      • とりあえず実装が簡単なのでoutptrにした
      • 後でMaybeUninitに変わるかもしれない
  • ポインタの射影は独立の構文にすることにした
    • p をポインタとして p.[i].Field のようなかたちの式を射影とみなす。アクセスパスと呼ぶ
    • Ptr.select, Ptr.read, Ptr.write というプリミティブがあって、その引数としてだけアクセスパスをかける。関数の引数にアクセスパスをおくことはできない
    • 構文が十分に軽量になった
    • 実装したのはまだインデックス参照だけ
  • ポインタ間のキャストのためのプリミティブ Ptr.cast を追加した
    • オーバーロードの必要性
  • ポインタから整数 (アドレス) へのキャストが副作用を持つという話をみた:
    • Pointers Are Complicated II, or: We need better language specs (2020-12-14)
    • 最適化によって意味が変わるコードがあって、その原因を検討したところ「ポインタから整数へのキャストの存在」以外は考えづらい、という感じ
    • ポインタはprovenance (起源や来歴という意味) を持つ
    • ポインタ→整数→ポインタにキャストするとprovenanceが失われるというのが関係しているらしい
  • Rustのポインタ関連のAPIへの提案として書かれた記事である、 Rust’s Unsafe Pointer Types Need An Overhaul - Faultlore を参考に設計している

Std.Vector など

  • 所有権の機能を使って、動的配列 (Vector) などのライブラリを実装している
  • Vectorから変換することで、所有権がないイミュータブルな配列 (Block) も安全に作れるようになった
    • いままではリストや木から変換するなどの効率の悪い方法でしか作れないことが多かった
  • VectorとBlockを相互に変換する関数をどこに置くか悩んだ
    • とりあえずVectorに置いた (Blockへの不必要な依存が発生している)
    • npmのpeer dependenciesのようなものがほしいかもしれない

Textmateの構文定義

  • 現時点の定義: milone-lang/milone.json
  • begin/endとpatternsを使って再帰的に適用するやりかたがようやく分かってきた
    • 例えば < から > の間は型の構文であるということを書いておくことで A<B<'T>> のようなコードにおいて終端の >> がそれぞれ閉じカッコとして認識されるようになった
    • 参考: Language Grammars — TextMate 1.x Manual
  • 型やパターンに関連する構文を定義することで、型やパターンを書く場所で適切にトークンが認識されるようになった
    • 型、パターン、式において出現できる記号などが異なるため
  • 式が出てくる場所を構文的に表現するのができなさそうなので、トップレベルの構文は式が出てくるものということにして、型やパターンのところだけ特殊化するという感じで定義している

MSVCの _Thread_local

どういうわけかC17に設定してもMSVCでは _Thread_local が使えない。代わりに __declspec(thread) という言語拡張の属性をつける

参考: fix: Fix the issue _Thread_local isn’t supported by MSVC (Windows)

Solotter更新

  • Solotter
  • herokuでセキュリティインシデントがあった
    • 影響なさそうだったが、いちおうherokuにdeployしている自作サービスのアクセストークンもrevokeしておいた
  • ついでに更新
    • UIがいい感じになった
    • React hooksの理解を反映: app.tsx
  • CHANGELOG.md の追加

その他

  • 数年ぶりに眼鏡を新調した。いままでの眼鏡より度が弱くなって目が疲れにくくなる……かもしれない
  • ガルパ (リズムゲーム) の六兆年と一夜物語(EXPERT)をフルコンボできた。当初からの目標だったので嬉しい

関連記事