summaryrefslogtreecommitdiff
path: root/server/src/matcher
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2018-11-29 13:46:19 +0800
committer最萌小汐 <sumneko@hotmail.com>2018-11-29 13:46:19 +0800
commit5a608c99b024b09d295b176c098dd251d782c35d (patch)
treeb9f9073882df6dc4b96befda592e89e871450043 /server/src/matcher
parent79d073d7b3ae2f508f0d2e154ed59f87530740e7 (diff)
downloadlua-language-server-5a608c99b024b09d295b176c098dd251d782c35d.zip
更新定义匹配
Diffstat (limited to 'server/src/matcher')
-rw-r--r--server/src/matcher/definition.lua137
-rw-r--r--server/src/matcher/env.lua134
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