diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2018-12-28 15:36:56 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2018-12-28 15:36:56 +0800 |
commit | a080b2516d2ce2efb65ad0fd26126cdfa6f6e4f8 (patch) | |
tree | b5672e03d11a43a56b63fe02d7b685eacd21ace4 /server/src/core/env.lua | |
parent | 549f6dd7ce8c733f9b51f5e93b3f14c1e2a44aca (diff) | |
download | lua-language-server-a080b2516d2ce2efb65ad0fd26126cdfa6f6e4f8.zip |
matcher -> core
Diffstat (limited to 'server/src/core/env.lua')
-rw-r--r-- | server/src/core/env.lua | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/server/src/core/env.lua b/server/src/core/env.lua new file mode 100644 index 00000000..ada26145 --- /dev/null +++ b/server/src/core/env.lua @@ -0,0 +1,139 @@ +local setmetatable = setmetatable +local pairs = pairs +local type = type +local table_sort = table.sort + +return function (root) + local env = {root} + local is_table = {} + for key, value in pairs(root) do + if type(value) == 'table' then + is_table[key] = true + end + end + root._next = nil + root._cut = {} + + local mt = { _env = env } + function mt:push() + env[#env+1] = { _next = env[#env], _cut = {} } + end + function mt:pop() + env[#env] = nil + end + function mt:cut(key) + env[#env]._cut[key] = true + end + function mt:__index(key) + local origin = env[#env] + if is_table[key] then + return setmetatable({}, { + __index = function (_, ckey) + local o = origin + while o do + local t = o[key] + if t and t[ckey] ~= nil then + return t[ckey] + end + o = not o._cut[key] and o._next + end + end, + __newindex = function (_, ckey, value) + local o = origin + if not o[key] then + o[key] = {} + end + o[key][ckey] = value + end, + __pairs = function () + local o = origin + local tbl = {} + while o do + local t = o[key] + if t then + for k, v in pairs(t) do + if tbl[k] == nil then + tbl[k] = v + end + end + end + o = not o._cut[key] and o._next + end + return next, tbl + end, + }) + else + local o = origin + while o do + if o[key] ~= nil then + return o[key] + end + o = not o._cut[key] and o._next + end + end + end + function mt:__newindex(key, value) + local o = env[#env] + if is_table[key] then + if type(o[key]) ~= 'table' then + o[key] = {} + end + if type(value) == 'table' then + for k, v in pairs(value) do + o[key][k] = v + end + else + error(('[env.%s] should be table, got [%s]'):format(key, value)) + end + else + o[key] = value + end + end + function mt:__pairs() + local keys = {} + local cuted = {} + local result = {} + local o = env[#env] + while true do + for key in pairs(o._cut) do + cuted[key] = true + end + for key, value in pairs(o) do + if key == '_cut' or key == '_next' then + goto CONTINUE + end + if cuted[key] then + goto CONTINUE + end + if result[key] == nil then + keys[#keys+1] = key + if is_table[key] then + result[key] = {} + else + result[key] = value + end + end + if is_table[key] then + for k, v in pairs(value) do + if result[key][k] == nil then + result[key][k] = v + end + end + end + ::CONTINUE:: + end + o = o._next + if not o then + break + end + end + table_sort(keys) + local i = 0 + return function () + i = i + 1 + local k = keys[i] + return k, result[k] + end + end + return setmetatable(mt, mt) +end |