script 用途には python を愛用していたのだけど、 python-3.10 で入った match 文が気に入りすぎて、 linux とか mac のデフォルトの python が 3.9 であったりすることが悲しかったので、 lua 使いになった。 (dotfiles の script を match から if に書きなおしたw)

というわけでもなく、nvim に常用して lua の使用頻度が上がったので、 ついでに主力のスクリプト言語が変わった。 nvim 以外に、 wezterm, nyagos という lua で設定するツールを採用した。

nvim は luajit(lua-5.1互換) で、wezterm は lua-5.4 で、 nyagos は gopherlua(lua-5.1互換) ということから, lua-5.1 向けの lua を使う。 lua は、5.1 で完成形ということでこれで良いのだ。

OpenGL は love2D(luajit), OpenXR は lovr(luajit) である。 WebRTC は janus(lua-5.3)。

luajit が人気なわけだが jit で速いだけでなく、 ffi の使い勝手が最高に良いというのもある。 luabinding の無い c のライブラリがあったとしても、 c の ヘッダーのコピーをベースにしてわりと簡単に ffi で使ってしまうことができるし、 lua に無い型付きの数値配列とかはこれで作れるので便利。

local array = ffi.new('float[5000]')
array[0] = 1.5 -- 0 origin なのだ w
--- pointer は配列を使うことが多い
local p_open = ffi.new('bool[1]', true)
if imgui.Begin('hello', p_open) then
end

要するに、OpenGL とか cimgui を使える。 (python の ctypes とだいたい同じ能力)

nvim の影響なのか lua の開発環境は近年良くなってきていて、 LuaLanguageServer と stylua の組みあわせが気に入っている。 LuaLanguageServer により型情報を追加してある程度Editorの支援を良くすることができる。

Lua Language Server | Wiki
Lua Language Server uses the Language Server Protocol to offer a better Lua development experience for your favourite editors.
Lua Language Server | Wiki favicon https://luals.github.io/wiki/annotations/

によるとついに EmmyLua annotations と袂を分って独自路線のようである。

人間の方が LanguageServer に積極的に型情報を提供する。 LuaLanguageServer に合わせてこんなスタイルになった。 LanguageServer でオブジェクトの field と method がちゃんと出るために継承の記述を使う。 先頭から new 関数まで定型コード。

---@class Point: PointInstance
local Point = {}
Point.__index = Point
---@param x integer
---@param y integer
---@return Point
function Point.new(x, y)
---@class PointInstance
local instance={
x = x,
y = y,
}
---@type Point
return setmetatable(instance, Point)
end
---@param rhs Point
---@return Point
function Point:__add(rhs)
return Point.new(self.x+rhs.x, self.y+rhs.y)
end
---@return number
function Point:norm()
return math.sqrt(self.x*self.x + self.y*self.y)
end
return Point

による self シンタックスシュガーを避けていたのだけど、 LanguageServer のおかげで間違えて . を使う間違いは気付きやすくなった。 それと呼びだしだけでなく定義するときにも使えることがわかったので、 使ってもいいかという気になった。 . が static method で、: が instance method と使い分ける慣習。

あと、LuaLanguageServer に Project 毎のライブラリの情報を伝えることができる。 project root に .luarc.json を配置する。 わりと設定できるので、ちゃんとやると良くなる。

{
"runtime.version": "LuaJIT",
"runtime.special": {
"love.filesystem.load": "loadfile"
},
"runtime.path": ["libs/?.lua", "libs/?/init.lua"],
"workspace.library": [
"${3rd}/busted/library",
"${3rd}/luassert/library",
"${3rd}/love2d/library",
"${3rd}/lfs/library",
"meta/gltf/library",
"meta/cimgui/library"
],
"format.enable": false,
"diagnostics.disable": ["empty-block", "unused-local", "unused-vararg"]
}

特に c モジュールは型情報を追加しないと、どんなメンバーがあるかわからなくて、 直接 c を使っているよりもコードが書きにくいということになりがちなので、 型情報は重要である。 (luaのモジュールは LuaLanguageServer が解析できるのだが LUA_PATH は教える必要がある)

LuaLanguageServer が組込みで型情報をもっているがそれ以外はここにあるぽい。 https://github.com/orgs/LuaCATS/repositories

require したものや組み込み変数の型はコメントで指定することができる。 いや、指定しないと判らないのではないか。

--- luarocks の場合
---@class uv
local uv = require "luv"
--- nvim の場合
---@class uv
local uv = vim.loop

それでも警告がいっぱいでてうまくいかないときは諦めて、any の型を付ける。

避けていた luarocks も慣れた。 特に Windows 環境では導入ではまりやすいのだけど慣れた。 python の venv のような使いかたもできる。 vc or mingw, system or user or project, standlone or embedded, lua or luajit という選択肢の多さが luarocks の難しさにつながる。 どの lua 向けのモジュールなのかを明確にして制御していく。 Windows では project local で hererocks するのも手かもしれない。