標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

Lisp を nyagos のコマンドラインに埋め込む Lua アドオン

ふと思いたって、 gmnlispnyagosコマンドラインに埋め込むアドオンを書いてみました。

gmnlisp_.lua

if not nyagos then
    print("This is a script for nyagos not lua.exe")
    os.exit()
end

share.org_filter_for_gmnlisp = nyagos.filter
nyagos.filter = function(cmdline)
    cmdline = string.gsub(cmdline,'$%b()', function(code)
        code = string.sub(code,2)
        code = string.gsub(code,'"','\\"')
        code = string.format('gmnlisp -e "(format t \\\"~a\\\" %s)"', code)
        return nyagos.eval(code)
    end)
    if share.org_filter_for_gmnlisp then
        local cmdline_ = share.org_filter_for_gmnlisp(cmdline)
        if cmdline_ then
            cmdline = cmdline_
        end
    end
    return cmdline
end

使用方法&使用例

スクリプトの内容を ~/.nyagos 内にペーストするか、lua_f コマンドで読み込みます。 使う時は最も外側の括弧の前に $ をつけます。

$ lua_f gmnlisp_.lua
$ echo $(+ 1 2 (* 3 4))
15
$ echo $(cons 1 2)
(1 . 2)

追記

~/.nyagos の中から ~/Share/etc/gmnlisp_.lua などというパスでスクリプトをロードする場合は

local gmnlisp_lua = nyagos.pathjoin(nyagos.env.userprofile,"Share\\etc\\gmnlisp_.lua")
local fd=io.open(gmnlisp_lua)
if fd then
    fd:close()
    print("loadfile " .. gmnlisp_lua)
    assert(loadfile(gmnlisp_lua))()
end

などと書いてもよいでしょう。

解説

  • if not nyagos then は nyagos ではなく、誤って lua.exe などで実行した時でも、誤動作させずにエラー終了させる文です。
  • nyagos.filterコマンドラインフィルターというものです。これが定義されいた場合、nyagos は、コマンドラインの内容をその関数に与え、戻り値の内容をコマンドラインに置換します。このコマンドラインフィルターは多重に定義できるようにするため、関数を設定する時、以前に設定されていた関数を内部から呼ぶようにするのが作法です。
  • gmnlisp が標準出力へ出す内容は、nyagos.eval にて引用できます。
  • gmnlisp は ISLisp のサブセットですが、ところどころ CommonLisp の文法が残っています。(format) 文は ISLisp どおりですが、t が標準出力を差すと解釈する点は CommonLisp と同じです。フォーマット文字列の ~a は AS IS の a ですね(ありのまま出す)。S式として出す場合は ~s とします。
  • Lua の Pattern は簡易正規表現というべきものですが、%b() という一つ便利な表現があります。これは括弧などの対応付けをきちんと考慮してマッチングしてくれるというもので、Lisp のように内側に無数に括弧があってもおおよそ期待どおり機能してくれます。

この仕組みを利用すれば、ユーザは任意のコマンドラインフィルターを作成できるでしょう。

動機

マインクラフトのオーバーワールド→ネザーの座標を計算するのに、毎回

$ lua_e "print(100/8.0,200/8.0)"

とかかくの、うざいなー。 せや、Lisp をそのまま引用したら、ええんちゃいか?

$ echo $(/ 100 8.0) $(/ 200 8.0)
12.500000 25.000000

うーん、あんまりかわらんかなー