diff options
Diffstat (limited to 'script-beta/parser/guide.lua')
-rw-r--r-- | script-beta/parser/guide.lua | 228 |
1 files changed, 120 insertions, 108 deletions
diff --git a/script-beta/parser/guide.lua b/script-beta/parser/guide.lua index a4a7291a..db3696ba 100644 --- a/script-beta/parser/guide.lua +++ b/script-beta/parser/guide.lua @@ -927,48 +927,6 @@ local function stepRefOfLabel(label, mode) return results end -local function getRefsByName(refs, name) - if not refs then - return nil - end - if #refs <= 100 then - return refs - else - if not refs.cache then - local cache = {} - refs.cache = cache - for i = 1, #refs do - local ref = refs[i] - local key = m.getSimpleName(ref) - if not cache[key] then - cache[key] = {} - end - cache[key][#cache[key]+1] = ref - end - end - return refs.cache[name] - end -end - -local function stepRefOfGlobal(obj, mode) - local results = {} - local name = m.getKeyName(obj) - local refs = getRefsByName(obj.node and obj.node.ref, name) or {} - for i = 1, #refs do - local ref = refs[i] - if m.getKeyName(ref) == name then - if mode == 'def' then - if obj == 'setglobal' then - results[#results+1] = ref - end - else - results[#results+1] = ref - end - end - end - return results -end - local function stepRefOfDocType(status, obj, mode) local results = {} if obj.type == 'doc.class.name' @@ -1011,10 +969,6 @@ function m.getStepRef(status, obj, mode) if obj.type == 'goto' then return stepRefOfLabel(obj.node, mode) end - if obj.type == 'getglobal' - or obj.type == 'setglobal' then - return stepRefOfGlobal(obj, mode) - end if obj.type == 'library' then return { obj } end @@ -1076,27 +1030,47 @@ local function convertSimpleList(list) local simple = {} for i = #list, 1, -1 do local c = list[i] - if c.special == '_G' - and c.type ~= 'getglobal' - and c.type ~= 'setglobal' then - simple.global = list[i+1] or c - else - simple[#simple+1] = m.getSimpleName(c) - end - if c.type == 'getglobal' - or c.type == 'setglobal' then - simple.global = c - end - if #simple <= 1 then - if simple.global then - simple.first = m.getENV(c, c.start) - elseif c.type == 'setlocal' - or c.type == 'getlocal' then - simple.first = c.node + if c.type == 'getglobal' + or c.type == 'setglobal' then + if c.special == '_G' then + simple.mode = 'global' + goto CONTINUE + end + local loc = c.node + if loc.special == '_G' then + simple.mode = 'global' + if not simple.node then + simple.node = c + end else - simple.first = c + simple.mode = 'local' + simple[#simple+1] = m.getSimpleName(loc) + if not simple.node then + simple.node = loc + end + end + elseif c.type == 'getlocal' + or c.type == 'setlocal' then + if c.special == '_G' then + simple.mode = 'global' + goto CONTINUE + end + simple.mode = 'local' + if not simple.node then + simple.node = c.node + end + elseif c.type == 'local' then + simple.mode = 'local' + if not simple.node then + simple.node = c + end + else + if not simple.node then + simple.node = c end end + simple[#simple+1] = m.getSimpleName(c) + ::CONTINUE:: end return simple end @@ -1221,6 +1195,12 @@ function m.isGlobal(source) return true end end + if source.type == 'field' then + local node = source.parent.node + if node and node.special == '_G' then + return true + end + end return false end @@ -1685,21 +1665,68 @@ function m.checkSameSimpleInCall(status, ref, start, queue, mode) end end -function m.checkSameSimpleInGlobal(status, name, start, queue) - if not name then +local function searchRawset(ref, results) + if m.getKeyName(ref) ~= 's|rawset' then + return + end + local call = ref.parent + if call.type ~= 'call' or call.node ~= ref then + return + end + if not call.args then + return + end + local arg1 = call.args[1] + if arg1.special ~= '_G' then + -- 不会吧不会吧,不会真的有人写成 `rawset(_G._G._G, 'xxx', value)` 吧 return end - if not status.interface.global then + results[#results+1] = call +end + +local function searchG(ref, results) + while ref and m.getKeyName(ref) == 's|_G' do + results[#results+1] = ref + ref = ref.next + end + if ref then + results[#results+1] = ref + searchRawset(ref, results) + end +end + +local function searchEnvRef(ref, results) + if ref.type == 'setglobal' + or ref.type == 'getglobal' then + results[#results+1] = ref + searchG(ref, results) + elseif ref.type == 'getlocal' then + results[#results+1] = ref.next + searchG(ref.next, results) + end +end + +function m.findGlobals(ast) + local results = {} + local env = m.getENV(ast) + if env.ref then + for _, ref in ipairs(env.ref) do + searchEnvRef(ref, results) + end + end + return results +end + +function m.checkSameSimpleInGlobal(status, name, source, start, queue) + if not name then return end - --if not status.cache.globalMark then - -- status.cache.globalMark = {} - --end - --if status.cache.globalMark[name] then - -- return - --end - --status.cache.globalMark[name] = true - local objs = status.interface.global(name) + local objs + if status.interface.global then + objs = status.interface.global(name) + else + objs = m.findGlobals(m.getRoot(source)) + end if objs then for _, obj in ipairs(objs) do queue[#queue+1] = { @@ -1900,7 +1927,7 @@ function m.pushResult(status, mode, ref, simple) results[#results+1] = ref end if ref.parent and ref.parent.type == 'return' then - if m.getParentFunction(ref) ~= m.getParentFunction(simple.first) then + if m.getParentFunction(ref) ~= m.getParentFunction(simple.node) then results[#results+1] = ref end end @@ -1973,7 +2000,7 @@ function m.pushResult(status, mode, ref, simple) end end -function m.checkSameSimple(status, simple, data, mode, results, queue) +function m.checkSameSimple(status, simple, data, mode, queue) local ref = data.obj local start = data.start local force = data.force @@ -2030,44 +2057,28 @@ function m.checkSameSimple(status, simple, data, mode, results, queue) end function m.searchSameFields(status, simple, mode) - local first = simple.first - if not first then - return - end - local refs = getRefsByName(first.ref, m.getSimpleName(simple.global or first)) or {} local queue = {} - for i = 1, #refs do - queue[i] = { - obj = refs[i], + if simple.mode == 'global' then + -- 全局变量开头 + m.checkSameSimpleInGlobal(status, simple[1], simple.node, 1, queue) + elseif simple.mode == 'local' then + -- 局部变量开头 + queue[1] = { + obj = simple.node, start = 1, } - end - -- 对初始对象进行预处理 - if simple.global then - for i = 1, #queue do - local data = queue[i] - local obj = data.obj - local nxt = m.getNextRef(obj) - if nxt and obj.special == '_G' then - data.obj = nxt - end - end - if first then - if first.tag == '_ENV' then - -- 检查全局变量的分支情况,需要业务层传入 interface.global - m.checkSameSimpleInGlobal(status, simple[1], 1, queue) - else - simple.global = nil - tableInsert(simple, 1, 'l|_ENV') + local refs = simple.node.ref + if refs then + for i = 1, #refs do queue[#queue+1] = { - obj = first, + obj = refs[i], start = 1, } end end else - queue[#queue+1] = { - obj = first, + queue[1] = { + obj = simple.node, start = 1, } end @@ -2081,7 +2092,7 @@ function m.searchSameFields(status, simple, mode) status.lock[data.obj] = true max = max + 1 status.cache.count = status.cache.count + 1 - m.checkSameSimple(status, simple, data, mode, status.results, queue) + m.checkSameSimple(status, simple, data, mode, queue) if max >= 10000 then logWarn('Queue too large!') break @@ -2193,7 +2204,8 @@ function m.searchRefsAsFunctionSet(status, obj, mode) end function m.searchRefsAsFunction(status, obj, mode) - if obj.type ~= 'function' then + if obj.type ~= 'function' + and obj.type ~= 'table' then return end m.searchRefsAsFunctionSet(status, obj, mode) |