我可以在模块中像setfenv(1, dslEnv)
,让我来访问这些函数像全局变量?
当然可以。你只需要找出正确的堆栈级别,而不是setfenv
调用中的1
。通常你会用一个带有debug.getinfo
调用的循环走到堆栈,直到找到堆栈中的require
函数,然后再移动一些,直到找到下一个主块(以防某人在某个函数中调用require
)。这是您必须使用的堆栈级别setfenv
。但可能我建议......
不同的方法
在Lua require
是可插拔的。您可以将一个函数(称为搜索器)添加到package.loaders
阵列中,require
将在尝试加载模块时调用它。假设您的所有DSL文件都有.bt
后缀,而不是通常的.lua
。然后,您将使用正常Lua搜索器的重新实现,其差别是您要寻找.bt
文件而不是.lua
文件,并且您可以拨打setfenv
功能return
编辑loadfile
。事情是这样的:
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
:
#!/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)
一个require'的'点的是,它隔离呼叫者的请求的模块。如果你愿意,你可以从返回的表中复制任意数量的成员。此外,“调试”模块包含破坏许多正常规则的功能。 – Deduplicator
你可以提供你想要达到的更多细节吗? – lhf
如果您通常使用这些函数,那么最好手动将每个函数本地化,因此至少所有编译器都可以对它们进行优化。 – Hydro