Skip to content

確かめて配る

ゲート、方言が断る書き方、バンドル、そしてまだできないこと。

ウィンドウなしの実行とゲート

PIXIE_SCRIPT が人の操作の代わりになります。 エンジンが木を組み、そこに書かれた手順のとおりに動かして、dump を出力します。

click:<label>      表示されている文字でボタンを押す
input:<text>       欄に打つ            submit    その欄で改行する
slide / select     つまみを動かす、選択肢を選ぶ
click@1:<label>    同じ文字のボタンの二つ目(n はツリー順に 0 から数える)
                   input@n:、submit@n、slide@n:、select@n: も同じ
key:<chord>        shortcut に結ばれた打鍵
keydown:<key> / keyup:<key>    キーを押したままにする、離す
menu:<item>        メニュー項目を選ぶ  file:<path>   ダイアログの答え
drop:<path>        ウィンドウにファイルを落とす
hover:<i>          チャートの i 番目の点にポインタを載せる(n 番目のチャートなら hover@n:<i>)
hover:             ポインタを外す
advance:<ms>       時計を進める        theme:dark|light
dump               ツリーを出力            a11y   読み上げが読むものを出力

rakugan gate は、一つのスクリプトでアプリを二回走らせます。 片方は perl が XS モジュール越しに動かすもので、もう片方は翻訳した .pix から作ったバイナリです。 最後に、二つの記録を一バイトずつ比べます。

$ rakugan gate demo/counter.pl --script "click:+1,dump,input:Momo"
GATE OK — 3 dump lines identical in both runs

ゲートが、Rakugan の約束そのものです。 このページのほかの部分では、そのゲートを通るものをどう書くかを説明しています。

Rakugan が断る書き方

rakugan check はアプリを読み、受け取れない書き方があれば、その行番号と書き換え方を示します。 先に読むのは perl です。 構文の可否は perl が決めるので、perl が撥ねた書き方が翻訳器に届くことはありません。 そのあとで翻訳器が、方言から外れた最初のものを指します。 ビルドの前にもゲートの前にも毎回走り、言うことがなければ何も出力しません。

$ rakugan check demo/broken.pl
demo/broken.pl:9:26: Rakugan cannot take this — a hash may not have that
key, so say what to answer when it does not: `$prices{$k} // 0`
        $picked = $prices{"apple"};
                  ^

断るものと、代わりの書き方は次のとおりです。

  • 初期値のないフィールドと、アプリ自身のクラスのフィールドに付けた :param。 型は初期値から来ます。
  • 何を入れるか言わずに空で始まるリストやハッシュ。 empty(Str) と書きます。
  • 二つの型が混ざったリスト。
  • 引数があるのに :Sig のないメソッド。
  • Bool ではない条件。 != 0ne "" のように比べます。
  • 片側が文字列の +。 文字列を数として読むのは 0 + $s です。
  • 文字列への ++。 perl はそこで文字を数え上げますが("az"++"ba")、コンパイルした実行はそれをしません。
  • // のないハッシュの読みと、sort のない keys
  • フィールドの初期値としての undef(型は maybe(Int) が言います)、defined// の外で読む「なにもないかもしれない値」、if の条件の全部としてではない defined、そして自分の defined の分岐の中でのその値への書き込み。
  • メソッドを持つクラスの中の $self、リストやハッシュのフィールド、ADJUST、フィールドや set_<field> と同じ名前のメソッド、そして二つの値で二度宣言された定数。
  • リストの中に収まっていることをビューが示せない添字。
  • ビューを組み立てている最中に呼ばれる、フィールドを書き換えるメソッド。
  • 一致を作った if の外の $1、実行時に組み立てたパターン、置換の /e
  • printprintfsay。 コンパイルしたアプリが書くのは画面で、標準出力ではありません。 標準エラーに出す warn は受け取ります。
  • 文字列の evalgotolocalwantarrayeachtieblessrefAUTOLOAD
  • finally、そしてループや失敗しうるメソッドを囲む try
  • 書き下していない数を指数にした整数の冪(2 ** $n)。 perl は負の指数に小数を答え、コンパイルした実行はどちらになるかを知っていなければなりません。 2.0 ** $n と書けば小数です。
  • ラベルつきのループ、state、値としての sub、自分のモジュール、eval { … }trycatch を書きます)、while で一致を一つずつ歩く形(先に全部取ります:my @found = ($s =~ /(\d)/g))、捕まえたものを自分の my で名づける一致。 どれも代わりの書き方を添えて断り、翻訳器が知らない Perl の関数は Perl 自身のものだと言い、代わりがあればそれも言います。
  • 同じブロックで die の後ろに続く行(perl はそこに届きません)と、同じハンドラで task の後ろに続く行(perl はすぐに届き、コンパイルした実行は処理が終わってから届きます)。
  • サブルーチンでないハンドラと、呼ばれ方に引数の数が合わないハンドラ。
  • 要素の知らないキーワードと、型の合わないキーワード。 文面は、その要素が取るものを並べます。

どれも、出力される文面ごと test/refuse/ に置いてあります。 だから、断りの文面が黙って変わることはありません。

リリース

$ rakugan build demo/todo.pl --release --app
built: ~/.cache/pixie/target/release/main (11.9 MB)
bundle: demo/dist/todo.app (11.9 MB)

--release は symbol table を落とします。 --app はバイナリを macOS のアプリケーションバンドルに包み、ad-hoc 署名をつけます。 アプリと同じ場所に <stem>.png<stem>.icns を置いておくと、それがアイコンになります。 バイナリはエンジンと翻訳したアプリを含んでいて、システム自身のライブラリ以外は何もリンクしません。 だから、このバンドルだけでプログラムが完結します。 perl 5.40 もツールチェインも入っていないマシンで、そのまま開きます。

まだできないこと

  • 方言は部分集合で、Rakugan が断る書き方がその外側です。 どれも、翻訳器がまだコンパイルした実行まで運べない書き方であって、Perl についての評価ではありません。
  • 実行中に 64 bit を超える整数。 perl はそれを小数のある数に育て、コンパイルした実行はそこでハンドラを止めます。 書き下した数がそこに達すれば断りますが、実行中に足し上げて達するものは check には見えず、捕まえるのはゲートです。
  • 末尾を越えたリストの読み。 perl は undef を答えて先へ進み、コンパイルした実行はハンドラを止めます。 $xs[$i] // $d と書けば代わりに答えるものを言えますが、check はまだそれを求めません。 末尾を越えたスライスは、perl が undef で埋めるところで端に揃えます。
  • 空のリストの summaxminmaxstrminstr は、perl が undef を答えるところで 0"" を答えます。 sum0 はどちらでも同じです。
  • 64 bit を超える **hexoct は、perl が小数のある数に育てるところでハンドラを止めます。 和の縁と同じ縁です。 また、整数どうしの ** を perl は、底が 2 の冪であるか答えが 64 bit を超えるときには小数のある数として計算し、1e15 以上では表示が変わります(2 ** 50 は perl では 1.12589990684262e+15)。 ここでは整数のままです。
  • fc/c つきの tr///sprintf%*d、そして for my ($i, $x) (indexed @xs)。 最後のものは翻訳器が読むのに使うパーサがまだ知りません(for my $i (0 .. $#xs) が同じことを読みます)。
  • リファレンスは、次のものだけです。 要素に渡すリストとハッシュ、それに自分で書いたクラスです。 ハンドラ以外のコードリファレンス、リファレンスへのリファレンス、ref はありません。
  • 自分で書くモジュールはありません。 アプリは 1 ファイルで、翻訳器が知っているモジュールの関数は List::UtilPOSIX のものだけです。 ほかのモジュールの use は読んで無視され、その中の関数を呼べば名前を挙げて断られます。
  • sprintf%s %d %i %f %F %e %E %g %G %x %X %o %b %% までです。 幅と精度、-+、空白、0# の指定は付けられます。
  • check が見つけるのは上に挙げたものです。 翻訳器が取りこぼすものをすべて見ているわけではないので、残りを見つけるのは今もゲートです。
  • macOS と Linux です。 --app は macOS の形なので、そこ以外では名前を挙げて止まります。 build が書くネイティブバイナリはどちらでも動きます。 バイナリが描画に使うエンジンを含むので、小さなアプリでも 12 MB ほどになります。