Ribbon: S式リーダーの高速化(ネイティブコード化)
誠に遺憾ながら、S式リーダーの高速化のため時間の掛かっているトークナイザだけネイティブコードに置き換えることにした。 ...これでも遅ければ真面目なリーダーを手書きしないといけなくなるので、できればこれでそこそこ使える速度になって欲しい。。
Ribbonには、どっちにせよWebAssembly実行用を想定したインタプリタも別途載せるつもりではあるので、どこかのタイミングでバイトコードインタプリタに載せ替えれば手書きのCコードを減らせるだろう。
prev
前は最適化入りで1分弱だった。10倍速の6秒くらいを狙いたい。
移植するコード
トークナイザのコードは今はSchemeで書かれていて、トークナイズした結果はSchemeのvectorで渡すようになっている:
- https://github.com/okuoku/yuni/blob/38c4bb758bd2228d2a92662b40c298f2f414a09f/lib/yuni/miniread/reader-main.sls
- https://github.com/okuoku/yuni/blob/38c4bb758bd2228d2a92662b40c298f2f414a09f/lib/yuni/miniread/charclasses.sls
生成したvectorは:
に渡されて、実際のS式に変換される。
vectorの1要素は9要素のvectorで、Schemeのコード内ではtve(Token Vector Entry)と呼んでいる。
これをCのenumと構造体に変換するのが第一歩かな。
1文字欠ける問題
... 結局全部Cに移植した。こういう事をやりたくなかったからSchemeでreaderを書いたのに。。概ね動いてると思うけど何かオブジェクトの末尾が欠ける。
(define x (string->utf8 "(aaa bbb ccc ddd) 1234 'abcd"))
(define (y x) (write (miniread-utf8-read x)) (newline))
(y x)
とりあえず1個ずらす。これ元のScheme版が間違ってるな。
テスト通らない
Test: 20/35 passed.
Failed:
['(#\a "hoge")] Expected: (#\a "hoge\"") Actual: (#\a "hoge")
['("hoge" "hoge")] Expected: ("hoge\"" "hoge\"") Actual: ("hoge" "hoge")
['("hoge" fuga "hoge")] Expected: ("hoge\"" fuga "hoge\"") Actual: ("hoge" fuga "hoge")
[obj] Expected: ((100 () (1 2 3) 100)) Actual: ((100 () (1 2 3) 100))
[obj] Expected: (100) Actual: (100)
[obj] Expected: (100) Actual: (100)
[obj] Expected: ((100 100)) Actual: ((100 100))
[obj] Expected: (("ABC\"")) Actual: (("ABC"))
[obj] Expected: ((100 "ABC\"")) Actual: ((100 "ABC"))
[obj] Expected: (# (100 100)) Actual: (#(100 100))
[obj] Expected: (# ()) Actual: (#())
[obj] Expected: (#vu8 (1 2 3 4)) Actual: (#u8(1 2 3 4))
[obj] Expected: (#u8 (1 2 3 4)) Actual: (#u8(1 2 3 4))
[obj] Expected: (#u8 ()) Actual: (#u8())
[obj] Expected: (#vu8 (0)) Actual: (#u8(0))
(微妙に解りづらいが、 Expected が今回移植したC版の出力で、 Actual が元のScheme版になる。)
更に "\""
のような、ダブルクオートを末尾にescapeするようなケースはクラッシュしてしまう。これはゴミ入りの文字列を生成してしまっている。
[obj] Expected: (100) Actual: (100)
これは多分数値がシンボルに化けている。
[obj] Expected: ((100 "ABC\"")) Actual: ((100 "ABC"))
これはさっき修正したoff-by-oneの逆パターンかな。。
[obj] Expected: (# (100 100)) Actual: (#(100 100))
[obj] Expected: (# ()) Actual: (#())
これ以降のvector関連のfailは、 #
のようなプレフィックス部分がシンボルに化けていて、残りが単なるリストになっているように見える。
文字列を修正
こういうミスは超はずかしいね。。
テスト通過した
というかテストしてて気付いたけど、readerよりもexpanderの方が重いなコレ。。ちょっと真面目に最適化しないと不味いかもしれない。