diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2018-11-29 13:46:19 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2018-11-29 13:46:19 +0800 |
commit | 5a608c99b024b09d295b176c098dd251d782c35d (patch) | |
tree | b9f9073882df6dc4b96befda592e89e871450043 /server/src/matcher | |
parent | 79d073d7b3ae2f508f0d2e154ed59f87530740e7 (diff) | |
download | lua-language-server-5a608c99b024b09d295b176c098dd251d782c35d.zip |
更新定义匹配
Diffstat (limited to 'server/src/matcher')
-rw-r--r-- | server/src/matcher/definition.lua | 137 | ||||
-rw-r--r-- | server/src/matcher/env.lua | 134 |
2 files changed, 271 insertions, 0 deletions
diff --git a/server/src/matcher/definition.lua b/server/src/matcher/definition.lua index 52084807..e5ab178d 100644 --- a/server/src/matcher/definition.lua +++ b/server/src/matcher/definition.lua @@ -1,3 +1,140 @@ +local env = require 'matcher.env' +local mt = {} +mt.__index = mt + +function mt:isContainPos(obj) + return obj.start <= self.pos and obj.finish >= self.pos +end + +function mt:checkName(name) + if self:isContainPos(name) then + return self.env.var[name] + else + return nil + end +end + +function mt:checkDots(dots) + if self:isContainPos(dots) then + return self.env.dots + else + return nil + end +end + +function mt:searchCall(call) + for _, exp in ipairs(call) do + local result = searchExp(exp) + if result then + return result + end + end + return nil +end + +function mt:searchSimple(simple) + local result = self:checkName(simple[1]) + if result then + return result + end + for i = 2, #simple do + local obj = simple[i] + local tp = obj.type + if tp == 'call' then + result = self:searchCall(obj) + elseif tp == ':' then + else + if obj.index then + result = self:searchExp(obj) + end + end + if result then + return result + end + end + return nil +end + +function mt:searchBinary(exp) + return self:searchExp(exp[1]) or self:searchExp(exp[2]) +end + +function mt:searchUnary(exp) + return self:searchExp(exp[1]) +end + +function mt:searchExp(exp) + local tp = exp.type + local result + if tp == 'nil' then + elseif tp == 'string' then + elseif tp == 'boolean' then + elseif tp == 'number' then + elseif tp == 'name' then + result = self:checkName(exp) + elseif tp == 'simple' then + result = self:searchSimple(exp) + elseif tp == 'binary' then + result = self:searchBinary(exp) + elseif tp == 'unary' then + result = self:searchUnary(exp) + elseif tp == '...' then + result = self:checkDots(exp) + elseif tp == 'function' then + elseif tp == 'table' then + end + return result +end + +function mt:searchReturn(action) + local exps = action[1] + if not exps then + return nil + end + for _, exp in ipairs(exps) do + local result = self:searchExp(exp) + if result then + return result + end + end + return nil +end + +function mt:checkThenSearchActionsIn(actions) + if self:isContainPos(actions) then + return self:searchActionsIn(actions) + else + return nil + end +end + +function mt:searchAction(action) + local tp = action.type + local result + if tp == 'do' then + result = self:checkThenSearchActionsIn(action) + elseif tp == 'break' then + elseif tp == 'return' then + result = self:searchReturn(action) + end + return result +end + +function mt:searchActionsIn(actions) + for _, action in ipairs(actions) do + local result = self:searchAction(action) + if result then + return result + end + end + return nil +end + return function (ast, pos) + local searcher = setmetatable({ + pos = pos, + env = env {var = {}, usable = {}}, + }, mt) + searcher:searchActionsIn(ast) return false end diff --git a/server/src/matcher/env.lua b/server/src/matcher/env.lua new file mode 100644 index 00000000..3a7388d1 --- /dev/null +++ b/server/src/matcher/env.lua @@ -0,0 +1,134 @@ +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:add() + table.insert(env, { _next = env[#env], _cut = {} }) + end + function mt:remove() + table.remove(env) + 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]是表,赋值也需要是表:[%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 |