は、私は私がそれらにアクセスすることを可能にするモジュールでsetfenv(1, dslEnv)
のようなものを持つことができますグローバル変数のような関数?
もちろん可能です。 setfenv
コールで1
の代わりに正しいスタックレベルを把握するだけで済みます。通常は、スタックに関数が見つかるまで、debug.getinfo
呼び出しのループを使用してスタックを歩き、次のメインチャンクを見つけるまで関数を移動します(関数内でrequire
を呼び出した場合)。これは、setfenv
で使用するスタックレベルです。しかし、私はLuaの中
require
はプラグ可能です...
異なるアプローチを提案することができます。 package.loaders
配列に関数(サーチャー)を追加すると、require
はモジュールをロードしようとしたときに呼び出されます。すべてのDSLファイルに通常の.lua
の代わりに.bt
の接尾辞があるとします。次に、通常のLuaサーチャーの再実装を使用して、.lua
ファイルの代わりに.bt
ファイルを探して、そしてloadfile
によってreturn
のsetfenv
を呼び出すという違いを見つけてください。このような何か:
local function Root(x) return x end
local function Sequence(x) return x end
local function Leaf(x) return x end
local delim = package.config:match("^(.-)\n"):gsub("%%", "%%%%")
local function searchpath(name, path)
local pname = name:gsub("%.", delim):gsub("%%", "%%%%")
local msg = {}
for subpath in path:gmatch("[^;]+") do
local fpath = subpath:gsub("%?", pname):gsub("%.lua$", ".bt") -- replace suffix
local f = io.open(fpath, "r")
if f then
f:close()
return fpath
end
msg[ #msg+1 ] = "\n\tno file '"..fpath.."'"
end
return nil, table.concat(msg)
end
local function bt_searcher(modname)
assert(type(modname) == "string")
local filename, msg = searchpath(modname, package.path)
if not filename then
return msg
end
local env = { -- create custom environment
Root = Root,
Sequence = Sequence,
Leaf = Leaf,
}
local mod, msg = loadfile(filename)
if not mod then
error("error loading module '"..modname.."' from file '"..filename..
"':\n\t"..msg, 0)
end
setfenv(mod, env) -- set custom environment
return mod, filename
end
table.insert(package.loaders, bt_searcher)
あなたのメインプログラムから一度モジュールでこれを入れてrequire
場合、あなたはその後、require
.bt
ファイルからカスタム環境でお使いのDSLファイルがどこかのようにあなたの.lua
ファイルを置くことができますよくDSLファイルにrequire("behaviortrees")
という名前は必要ありません。例えば:
ファイルxxx.bt
:
return Root {
Sequence {
Leaf "leafname",
Leaf "leafname"
}
}
ファイルmain.lua
:require` `のポイントの
#!/usr/bin/lua5.1
require("behaviortrees") -- loads the Lua module above and adds to package.loaders
print(require("xxx")) -- loads xxx.bt (but an xxx Lua module would still take precedence)
一つは、発信者から要求されたモジュールを隔離することです。必要に応じて、返されたテーブルから任意の数のメンバーをコピーできます。また、 'debug'モジュールには、通常の規則の多くを破る関数が含まれています。 – Deduplicator
達成しようとしていることの詳細を教えてください。 – lhf
これらの関数を一般的に使用する場合は、それぞれを手動でローカルにする方がよいので、少なくともすべてのコンパイラで最適化することができます。 – Hydro