Lua側からluasub定義や引数の取得を容易にするスクリプト
の三つを踏まえた上で、luasubを簡単にできるようにしてみた。
定義
たとえば、getspsizeをnsluaで再実装するためには、下記のようにする。
-- luasub.命令名(関数実体, 引数定義)
luasub.getspsize(NSSpGetInfo, NSPop.iIII)
引数定義については、NSPopを使う。
NSPopの後にドット、それからi, I, s, S, D, Lの6種類のみで構成された文字列をつけると、それは特定のパターンで引数を取得する関数になる。
文字の意味は下記の通り。
- i
- 数値
- s
- 文字列
- D
- ID
- L
- ラベル
- I
- 数値変数の変数番号
- S
- 文字列変数の変数番号
これらを隙間なくつなげることで、引数定義になる。
上記の例であれば、最初に数値を一つ。それから数値変数を扱う関数が三つになる。
luasubで定義された命令が、NScripter側から実行されると、まず引数が取得される。取得された引数のうち、IとSを除いた物が関数実体に渡される。(上記の場合は、先頭の数値のみ)
関数実体は何らかの返り値を返すことが期待される。
関数実体からの返り値は、IとSで定義されたNScripter側の変数に順番を合わせて記録される。
こうすることで、nslua内で使うことを想定に作られた通常の関数を、そのまま関数実体として扱うことができる。
※可変引数を実装したい場合は、引数定義に固定部分までを記述して、関数実体内に地道にNSPop系を使って実装してください。
-- lspとlsphを再実装してみる。 function lsp_main(visible, spnum, tag, x, y) local alpha = 255 if NSCheckComma() then NSPopComma(); alpha = NSPopInt() end NSSpLoad(spnum, tag) NSSpMove(spnum, x, y, alpha) NSSpVisible(spnum, visible) end function lsp(...) return lsp_main(true, ...) end function lsph(...) return lsp_main(false, ...) end luasub.lsp(lsp, NSPop.isii) -- 登録 luasub.lsph(lsph, NSPop.isii) -- 登録
スクリプト(前提三つもふくんでいます)
-- NSExec/NSSetIntValue/NSSetStrValueのログを取るスクリプト do local fh = io.open("nsexec.log", "w") fh:setvbuf("full") local original1 = _G.NSExec _G.NSExec = function(str) fh:write(str); fh:flush() original1(str) fh:write("\n"); fh:flush() end local original2 = _G.NSSetIntValue _G.NSSetIntValue = function(num, v) fh:write("%"..tostring(num).."="..tostring(v).."\n") original2(num, v) fh:flush() end local original3 = _G.NSSetStrValue _G.NSSetStrValue = function(num, v) fh:write("$"..tostring(num).."="..v.."\n") original3(num, v) fh:flush() end end -- NScripter側のデフォルト命令をLua側から簡単に実行させる。 do _G.Cd = setmetatable({}, {__index=function(t, k) local func = function() return k:lower() end rawset(t, k, func) return rawget(t, k) end}) _G.Lb = setmetatable({}, {__index=function(t, k) local func = function() return "*"..k:lower() end rawset(t, k, func) return rawget(t, k) end}) local shi = {} local shs = {} local res = {} _G.iRet = function(v) local num = #shi shi[num+1] = NSGetIntValue(num) if v then NSSetIntValue(num, v) else res[1+#res] = function() return NSGetIntValue(num) end end return "%"..tostring(num) end _G.sRet = function(v) local num = #shs shs[num+1] = NSGetStrValue(num) if v then NSSetStrValue(num, v) else res[1+#res] = function() return NSGetStrValue(num) end end return "$"..tostring(num) end local comeback = function() local ret = {} for i, v in ipairs(res) do ret[1+#ret] = v() end res = {} for i, v in ipairs(shi) do NSSetIntValue(i-1, v) end shi = {} for i, v in ipairs(shs) do NSSetStrValue(i-1, v) end shs = {} return ret end _G.Ns = setmetatable({}, {__index=function(t, k) local func = function(...) local str = "_"..k local tp for i, v in ipairs({...}) do if i == 1 then str = str .. " " else str = str .. "," end tp = type(v) if tp == "number" then str = str .. tostring(math.floor(v)) elseif tp == "string" then str = str .. sRet(v) elseif tp == "function" then str = str .. v() end end NSExec(str) return unpack(comeback()) end rawset(t, k, func) return rawget(t, k) end}) end -- numaliasをLua側から簡単に実行できるようにする。 -- NScripter側の数値を簡単に取得、変更できるようにする。 do local alias_count = 100 _G.next_numalias = function(num) if num then alias_count = num end return alias_count end local ob1 = {} setmetatable(ob1, {__index=function(t, k) local shelter = NSGetIntValue(0) NSExec("mov %0,"..k) rawset(t, k, NSGetIntValue(0)) NSSetIntValue(0, shelter) return rawget(t, k) end}) _G.Nm = ob1 local ei = setmetatable({}, {__index=function(t, k) rawset(t, k, function(v) if v then NSSetIntValue(k, v) end return NSGetIntValue(k) end) return rawget(t, k) end}) local obi = setmetatable({}, {__index=function(t, k) if type(k) == "string" then rawset(t, k, ei[ob1[k]]) else rawset(t, k, ei[k]) end return rawget(t, k) end}) _G.iNm = obi local es = setmetatable({}, {__index=function(t, k) rawset(t, k, function(v) if v then NSSetStrValue(k, v) end return NSGetStrValue(k) end) return rawget(t, k) end}) local obs = setmetatable({}, {__index=function(t, k) if type(k) == "string" then rawset(t, k, es[ob1[k]]) else rawset(t, k, es[k]) end return rawget(t, k) end}) _G.sNm = obs local ob2 = {} setmetatable(ob2, {__index=function(t, numalias) return function(num) local temp = rawget(ob1, numalias) if type(temp) == "nil" then if num then rawset(ob1, numalias, num) else rawset(ob1, numalias, alias_count) alias_count = alias_count + 1 end NSExec("numalias "..numalias..","..tostring(rawget(ob1, numalias))) else NSOkBox(numalias.." は既に定義されています。", "numalias") NSEnd() end return rawget(ob1, numalias) end end}) _G.numalias = ob2 end -- luasub定義・二重登録チェック・引数の簡単な取得をやる(肝) do _G.NSPop = setmetatable({}, {__index=function(t, k) local arg = {} for i, v in ipairs({k:byte(1, k:len())}) do arg[i] = string.char(v) end local res = {} rawset(t, k, function() for i, tp in ipairs(arg) do if tp == "i" then res[1+#res] = NSPopInt() elseif tp == "s" then res[1+#res] = NSPopStr() elseif tp == "I" then res[1+#res] = iNm[NSPopIntRef()] elseif tp == "S" then res[1+#res] = sNm[NSPopStrRef()] elseif tp == "D" then res[1+#res] = NSPopID() elseif tp == "L" then res[1+#res] = NSPopLabel() end if i == #arg then break end if NSCheckComma() then NSPopComma() else break end end return res end) return rawget(t, k) end}) _G.luasub = setmetatable({}, {__index=function(t, k) local pn = "NSCOM_"..k if _G[pn] then NSOkBox("命令 "..k.." は既に定義されています。", "luasub") NSEnd() end Ns.luasub(Cd[k]) return function(func, pop) if pop then _G[pn] = function() local arg = {} local res = {} for i, v in ipairs(pop()) do if type(v) == "function" then res[1+#res] = v else arg[1+#arg] = v end end for i, v in ipairs({func(unpack(arg))}) do if res[i] then res[i](v) end end end else _G[pn] = func end end end}) end