summaryrefslogtreecommitdiff
path: root/script-beta
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2020-08-16 15:27:01 +0800
committer最萌小汐 <sumneko@hotmail.com>2020-08-16 15:27:01 +0800
commit8fdeec14b4a90e1f15ed639ebc7b7b423e100424 (patch)
tree802817ffef749310c5ab9b83fd165ae90ea551f2 /script-beta
parent36b69f2c7f11e337897d282a10151548cb8876ea (diff)
downloadlua-language-server-8fdeec14b4a90e1f15ed639ebc7b7b423e100424.zip
挪到 guide 里
Diffstat (limited to 'script-beta')
-rw-r--r--script-beta/core/hover/label.lua13
-rw-r--r--script-beta/core/hover/return.lua8
-rw-r--r--script-beta/core/hover/table.lua2
-rw-r--r--script-beta/parser/guide.lua255
-rw-r--r--script-beta/vm/getClass.lua2
-rw-r--r--script-beta/vm/getValue.lua116
-rw-r--r--script-beta/vm/guideInterface.lua2
7 files changed, 277 insertions, 121 deletions
diff --git a/script-beta/core/hover/label.lua b/script-beta/core/hover/label.lua
index d3fbe6af..5e14c68e 100644
--- a/script-beta/core/hover/label.lua
+++ b/script-beta/core/hover/label.lua
@@ -4,6 +4,7 @@ local buildReturn = require 'core.hover.return'
local buildTable = require 'core.hover.table'
local vm = require 'vm'
local util = require 'utility'
+local guide = require 'parser.guide'
local function asFunction(source, oop)
local name = buildName(source, oop)
@@ -23,11 +24,11 @@ local function asValue(source, title)
for _, value in ipairs(values) do
local src = value.source
local tp = value.type
- class = vm.mergeViews(class, vm.getClass(src))
- type = vm.mergeViews(type, tp)
+ class = guide.mergeInfers(class, vm.getClass(src))
+ type = guide.mergeInfers(type, tp)
local sl = vm.getLiteral(src)
if sl then
- literal = vm.mergeViews(literal, util.viewLiteral(sl))
+ literal = guide.mergeInfers(literal, util.viewLiteral(sl))
end
if tp == 'table' then
cont = buildTable(src)
@@ -35,11 +36,11 @@ local function asValue(source, title)
end
end
vm.eachDef(source, function (src)
- class = vm.mergeViews(class, vm.getClass(src))
- type = vm.mergeViews(type, vm.getType(src))
+ class = guide.mergeInfers(class, vm.getClass(src))
+ type = guide.mergeInfers(type, vm.getType(src))
local sl = vm.getLiteral(src)
if sl then
- literal = vm.mergeViews(literal, util.viewLiteral(sl))
+ literal = guide.mergeInfers(literal, util.viewLiteral(sl))
end
if type == 'table' then
cont = buildTable(src)
diff --git a/script-beta/core/hover/return.lua b/script-beta/core/hover/return.lua
index e6f7a38a..82dc1314 100644
--- a/script-beta/core/hover/return.lua
+++ b/script-beta/core/hover/return.lua
@@ -21,9 +21,9 @@ local function asLibrary(source)
local lines = {}
for i = 1, #returns do
if i == 1 then
- lines[i] = (' -> %s'):format(vm.viewType(returns[i]))
+ lines[i] = (' -> %s'):format(guide.viewInfer(returns[i]))
else
- lines[i] = ('% 3d. %s'):format(i, vm.viewType(returns[i]))
+ lines[i] = ('% 3d. %s'):format(i, guide.viewInfer(returns[i]))
end
end
return table.concat(lines, '\n')
@@ -47,9 +47,9 @@ local function asFunction(source)
local lines = {}
for i = 1, #returns do
if i == 1 then
- lines[i] = (' -> %s'):format(vm.viewType(returns[i]))
+ lines[i] = (' -> %s'):format(guide.viewInfer(returns[i]))
else
- lines[i] = ('% 3d. %s'):format(i, vm.viewType(returns[i]))
+ lines[i] = ('% 3d. %s'):format(i, guide.viewInfer(returns[i]))
end
end
return table.concat(lines, '\n')
diff --git a/script-beta/core/hover/table.lua b/script-beta/core/hover/table.lua
index fb89c7f9..d00440a7 100644
--- a/script-beta/core/hover/table.lua
+++ b/script-beta/core/hover/table.lua
@@ -118,7 +118,7 @@ return function (source)
local intValue = true
vm.eachField(source, function (src)
local key, class, literal = getField(src)
- classes[key] = vm.mergeViews(class, classes[key])
+ classes[key] = guide.mergeInfers(class, classes[key])
literals[key] = mergeLiteral(literal, literals[key])
if class ~= 'integer'
or not literals[key]
diff --git a/script-beta/parser/guide.lua b/script-beta/parser/guide.lua
index 42ad798b..228b0a61 100644
--- a/script-beta/parser/guide.lua
+++ b/script-beta/parser/guide.lua
@@ -1,17 +1,23 @@
-local util = require 'utility'
-local error = error
-local type = type
-local next = next
-local tostring = tostring
-local print = print
-local ipairs = ipairs
-local tableInsert = table.insert
-local tableUnpack = table.unpack
-local tableRemove = table.remove
-local tableMove = table.move
-local pairs = pairs
-
-_ENV = nil
+local util = require 'utility'
+local error = error
+local type = type
+local next = next
+local tostring = tostring
+local print = print
+local ipairs = ipairs
+local tableInsert = table.insert
+local tableUnpack = table.unpack
+local tableRemove = table.remove
+local tableMove = table.move
+local tableSort = table.sort
+local tableConcat = table.concat
+local mathType = math.type
+local pairs = pairs
+local setmetatable = setmetatable
+local assert = assert
+local select = select
+
+local _ENV = nil
local m = {}
@@ -85,6 +91,18 @@ m.actionMap = {
['funcargs'] = {'#'},
}
+local TypeSort = {
+ ['boolean'] = 1,
+ ['string'] = 2,
+ ['integer'] = 3,
+ ['number'] = 4,
+ ['table'] = 5,
+ ['function'] = 6,
+ ['nil'] = 999,
+}
+
+local NIL = setmetatable({'<nil>'}, { __tostring = function () return 'nil' end })
+
--- 是否是字面量
function m.isLiteral(obj)
local tp = obj.type
@@ -1041,6 +1059,9 @@ function m.searchFields(status, obj, key, interface)
end
function m.getObjectValue(obj)
+ while obj.type == 'paren' do
+ obj = obj.exp
+ end
if obj.value then
return obj.value
end
@@ -1823,6 +1844,206 @@ function m.searchRefOfValue(status, obj)
end
end
+function m.mergeInfer(t, b)
+ if not t then
+ t = {}
+ end
+ if not b then
+ return t
+ end
+ for i = 1, #b do
+ local o = b[i]
+ if not t[o] then
+ t[o] = true
+ t[#t+1] = o
+ end
+ end
+ return t
+end
+
+function m.allocInfer(o)
+ -- TODO
+ assert(o.type)
+ if type(o.type) == 'table' then
+ local values = {}
+ for i = 1, #o.type do
+ local sub = {
+ type = o.type[i],
+ value = o.value,
+ source = o.source,
+ }
+ values[i] = sub
+ values[sub] = true
+ end
+ return values
+ else
+ return {
+ [1] = o,
+ [o] = true,
+ }
+ end
+end
+
+function m.insertInfer(t, o)
+ if not o then
+ return
+ end
+ if not t[o] then
+ t[o] = true
+ t[#t+1] = o
+ end
+ return t
+end
+
+local function mergeInfers(types)
+ if #types == 0 then
+ return nil
+ end
+ if #types == 1 then
+ return types[1]
+ end
+ tableSort(types, function (a, b)
+ local sa = TypeSort[a]
+ local sb = TypeSort[b]
+ if sa and sb then
+ return sa < sb
+ end
+ if not sa and not sb then
+ return a < b
+ end
+ if sa and not sb then
+ return true
+ end
+ if not sa and sb then
+ return false
+ end
+ return false
+ end)
+ return tableConcat(types, '|')
+end
+
+function m.mergeInfers(...)
+ local max = select('#', ...)
+ local views = {}
+ for i = 1, max do
+ local view = select(i, ...)
+ if view then
+ for tp in view:gmatch '[^|]+' do
+ if not views[tp] and tp ~= 'any' then
+ views[tp] = true
+ views[#views+1] = tp
+ end
+ end
+ end
+ end
+ return mergeInfers(views)
+end
+
+function m.viewInfer(infers)
+ if not infers then
+ return 'any'
+ end
+ if type(infers) ~= 'table' then
+ return infers or 'any'
+ end
+ local types = {}
+ for i = 1, #infers do
+ local tp = infers[i].type
+ if tp and not types[tp] and tp ~= 'any' then
+ types[tp] = true
+ types[#types+1] = tp
+ end
+ end
+ return m.mergeInfers(types) or 'any'
+end
+
+function m.inferCheckLiteral(status, source)
+ if source.type == 'string' then
+ return m.alloc {
+ type = 'string',
+ value = source[1],
+ source = source,
+ }
+ elseif source.type == 'nil' then
+ return m.alloc {
+ type = 'nil',
+ value = NIL,
+ source = source,
+ }
+ elseif source.type == 'boolean' then
+ return m.alloc {
+ type = 'boolean',
+ value = source[1],
+ source = source,
+ }
+ elseif source.type == 'number' then
+ if mathType(source[1]) == 'integer' then
+ return m.alloc {
+ type = 'integer',
+ value = source[1],
+ source = source,
+ }
+ else
+ return m.alloc {
+ type = 'number',
+ value = source[1],
+ source = source,
+ }
+ end
+ elseif source.type == 'integer' then
+ return m.alloc {
+ type = 'integer',
+ source = source,
+ }
+ elseif source.type == 'table' then
+ return m.alloc {
+ type = 'table',
+ source = source,
+ }
+ elseif source.type == 'function' then
+ return m.alloc {
+ type = 'function',
+ source = source,
+ }
+ elseif source.type == '...' then
+ return m.alloc {
+ type = '...',
+ source = source,
+ }
+ end
+end
+
+function m.searchInfer(status, obj)
+ obj = m.getObjectValue(obj) or obj
+ local results = m.inferCheckLiteral(status, obj)
+ --or inferCheckUnary(obj)
+ --or inferCheckBinary(obj)
+ --or inferCheckLibraryTypes(obj)
+ --or inferCheckLibrary(obj)
+ --or inferCheckSpecialReturn(obj)
+ --or inferCheckLibraryReturn(obj)
+ if results then
+ return results
+ end
+
+ results = {}
+ --inferByLibraryArg(results, obj)
+ --inferByDef(results, source)
+ --inferBySet(results, obj)
+ --inferByCall(results, obj)
+ --inferByGetTable(results, obj)
+ --inferByUnary(results, obj)
+ --inferByBinary(results, obj)
+ --inferByCallReturn(results, obj)
+ --inferByPCallReturn(results, obj)
+
+ if #results == 0 then
+ return nil
+ end
+
+ return results
+end
+
--- 请求对象的引用,包括 `a.b.c` 形式
--- 与 `return function` 形式。
--- 不穿透 `setmetatable` ,考虑由
@@ -1857,4 +2078,10 @@ function m.requestFields(obj, interface)
return m.searchFields(nil, obj, nil, interface)
end
+--- 请求对象的类型推测
+function m.requestInfer(obj, interface)
+ local status = m.status(nil, interface)
+ return m.searchInfer(status, obj)
+end
+
return m
diff --git a/script-beta/vm/getClass.lua b/script-beta/vm/getClass.lua
index feccc981..0d5d45b1 100644
--- a/script-beta/vm/getClass.lua
+++ b/script-beta/vm/getClass.lua
@@ -41,5 +41,5 @@ function vm.getClass(source)
if #classes == 0 then
return nil
end
- return vm.mergeViews(table.unpack(classes))
+ return guide.mergeInfers(table.unpack(classes))
end
diff --git a/script-beta/vm/getValue.lua b/script-beta/vm/getValue.lua
index 9837e093..bc83dc10 100644
--- a/script-beta/vm/getValue.lua
+++ b/script-beta/vm/getValue.lua
@@ -433,19 +433,6 @@ local function checkBinary(source)
end
end
-local function checkValue(source)
- if source.value then
- return vm.getValue(source.value)
- end
- if source.type == 'paren' then
- return vm.getValue(source.exp)
- end
- if source.type == 'field'
- or source.type == 'method' then
- return vm.getValue(source.parent)
- end
-end
-
local function inferByCall(results, source)
if #results ~= 0 then
return
@@ -489,7 +476,7 @@ end
local function inferByDef(results, source)
local defs = vm.getDefs(source)
for _, src in ipairs(defs) do
- local tp = vm.getValue(src)
+ local tp = vm.inferValue(src, false)
if tp then
merge(results, tp)
end
@@ -812,29 +799,32 @@ local function inferByPCallReturn(results, source)
end
end
-local function getValue(source)
+function vm.inferValue(source, infer)
+ source = guide.getObjectValue(source) or source
local results = checkLiteral(source)
- --or checkValue(source)
- --or checkUnary(source)
- --or checkBinary(source)
- --or checkLibraryTypes(source)
- --or checkLibrary(source)
- --or checkSpecialReturn(source)
- --or checkLibraryReturn(source)
+ or checkUnary(source)
+ or checkBinary(source)
+ or checkLibraryTypes(source)
+ or checkLibrary(source)
+ or checkSpecialReturn(source)
+ or checkLibraryReturn(source)
if results then
return results
end
+ if not infer then
+ return
+ end
results = {}
- --inferByLibraryArg(results, source)
+ inferByLibraryArg(results, source)
--inferByDef(results, source)
- --inferBySet(results, source)
- --inferByCall(results, source)
- --inferByGetTable(results, source)
- --inferByUnary(results, source)
- --inferByBinary(results, source)
- --inferByCallReturn(results, source)
- --inferByPCallReturn(results, source)
+ inferBySet(results, source)
+ inferByCall(results, source)
+ inferByGetTable(results, source)
+ inferByUnary(results, source)
+ inferByBinary(results, source)
+ inferByCallReturn(results, source)
+ inferByPCallReturn(results, source)
if #results == 0 then
return nil
@@ -944,71 +934,9 @@ function vm.hasType(source, type)
return false
end
-local function mergeViews(types)
- if #types == 0 then
- return nil
- end
- if #types == 1 then
- return types[1]
- end
- table.sort(types, function (a, b)
- local sa = typeSort[a]
- local sb = typeSort[b]
- if sa and sb then
- return sa < sb
- end
- if not sa and not sb then
- return a < b
- end
- if sa and not sb then
- return true
- end
- if not sa and sb then
- return false
- end
- return false
- end)
- return table.concat(types, '|')
-end
-
-function vm.viewType(values)
- if not values then
- return 'any'
- end
- if type(values) ~= 'table' then
- return values or 'any'
- end
- local types = {}
- for i = 1, #values do
- local tp = values[i].type
- if tp and not types[tp] and tp ~= 'any' then
- types[tp] = true
- types[#types+1] = tp
- end
- end
- return mergeViews(types) or 'any'
-end
-
-function vm.mergeViews(...)
- local max = select('#', ...)
- local views = {}
- for i = 1, max do
- local view = select(i, ...)
- if view then
- for tp in view:gmatch '[^|]+' do
- if not views[tp] and tp ~= 'any' then
- views[tp] = true
- views[#views+1] = tp
- end
- end
- end
- end
- return mergeViews(views)
-end
-
function vm.getType(source)
local values = vm.getValue(source)
- return vm.viewType(values)
+ return guide.viewInfer(values)
end
--- 获取对象的值
@@ -1025,7 +953,7 @@ function vm.getValue(source)
if not unlock then
return
end
- cache = getValue(source) or false
+ cache = guide.requestInfer(source, vm.interface) or false
vm.getCache('getValue')[source] = cache
unlock()
return cache
diff --git a/script-beta/vm/guideInterface.lua b/script-beta/vm/guideInterface.lua
index eae22b68..bd7a7c2b 100644
--- a/script-beta/vm/guideInterface.lua
+++ b/script-beta/vm/guideInterface.lua
@@ -110,7 +110,7 @@ end
function vm.setSearchLevel(n)
-- 只有在搜索等级由低变高时,才需要清空缓存
if n > vm.interface.searchLevel then
- vm.flushCache()
+ --vm.flushCache()
end
vm.interface.searchLevel = n
end