summaryrefslogtreecommitdiff
path: root/script-beta/vm/eachField.lua
diff options
context:
space:
mode:
Diffstat (limited to 'script-beta/vm/eachField.lua')
-rw-r--r--script-beta/vm/eachField.lua169
1 files changed, 169 insertions, 0 deletions
diff --git a/script-beta/vm/eachField.lua b/script-beta/vm/eachField.lua
new file mode 100644
index 00000000..1d3d222d
--- /dev/null
+++ b/script-beta/vm/eachField.lua
@@ -0,0 +1,169 @@
+local guide = require 'parser.guide'
+local vm = require 'vm.vm'
+
+local function ofTabel(value, callback)
+ for _, field in ipairs(value) do
+ if field.type == 'tablefield'
+ or field.type == 'tableindex' then
+ callback {
+ source = field,
+ key = guide.getKeyName(field),
+ value = field.value,
+ mode = 'set',
+ }
+ end
+ end
+end
+
+local function ofENV(source, callback)
+ if source.type == 'getlocal' then
+ local parent = source.parent
+ if parent.type == 'getfield'
+ or parent.type == 'getmethod'
+ or parent.type == 'getindex' then
+ callback {
+ source = parent,
+ key = guide.getKeyName(parent),
+ mode = 'get',
+ }
+ end
+ elseif source.type == 'getglobal' then
+ callback {
+ source = source,
+ key = guide.getKeyName(source),
+ mode = 'get',
+ }
+ elseif source.type == 'setglobal' then
+ callback {
+ source = source,
+ key = guide.getKeyName(source),
+ mode = 'set',
+ value = source.value,
+ }
+ end
+end
+
+local function ofSpecialArg(source, callback)
+ local args = source.parent
+ local call = args.parent
+ local func = call.node
+ local name = func.special
+ if name == 'rawset' then
+ if args[1] == source and args[2] then
+ callback {
+ source = call,
+ key = guide.getKeyName(args[2]),
+ value = args[3],
+ mode = 'set',
+ }
+ end
+ elseif name == 'rawget' then
+ if args[1] == source and args[2] then
+ callback {
+ source = call,
+ key = guide.getKeyName(args[2]),
+ mode = 'get',
+ }
+ end
+ elseif name == 'setmetatable' then
+ if args[1] == source and args[2] then
+ vm.eachField(args[2], function (info)
+ if info.key == 's|__index' and info.value then
+ vm.eachField(info.value, callback)
+ end
+ end)
+ end
+ end
+end
+
+local function ofVar(source, callback)
+ local parent = source.parent
+ if not parent then
+ return
+ end
+ if parent.type == 'getfield'
+ or parent.type == 'getmethod'
+ or parent.type == 'getindex' then
+ callback {
+ source = parent,
+ key = guide.getKeyName(parent),
+ mode = 'get',
+ }
+ return
+ end
+ if parent.type == 'setfield'
+ or parent.type == 'setmethod'
+ or parent.type == 'setindex' then
+ callback {
+ source = parent,
+ key = guide.getKeyName(parent),
+ value = parent.value,
+ mode = 'set',
+ }
+ return
+ end
+ if parent.type == 'callargs' then
+ ofSpecialArg(source, callback)
+ end
+end
+
+local function eachField(source, callback)
+ vm.eachRef(source, function (info)
+ local src = info.source
+ if src.tag == '_ENV' then
+ if src.ref then
+ for _, ref in ipairs(src.ref) do
+ ofENV(ref, callback)
+ end
+ end
+ elseif src.type == 'getlocal'
+ or src.type == 'getglobal'
+ or src.type == 'getfield'
+ or src.type == 'getmethod'
+ or src.type == 'getindex' then
+ ofVar(src, callback)
+ elseif src.type == 'table' then
+ ofTabel(src, callback)
+ end
+ end)
+end
+
+--- 获取所有的field
+function vm.eachField(source, callback)
+ local cache = vm.cache.eachField[source]
+ if cache then
+ for i = 1, #cache do
+ local res = callback(cache[i])
+ if res ~= nil then
+ return res
+ end
+ end
+ return
+ end
+ local unlock = vm.lock('eachField', source)
+ if not unlock then
+ return
+ end
+ cache = {}
+ vm.cache.eachField[source] = cache
+ local mark = {}
+ eachField(source, function (info)
+ local src = info.source
+ if mark[src] then
+ return
+ end
+ mark[src] = true
+ cache[#cache+1] = info
+ end)
+ unlock()
+ vm.eachRef(source, function (info)
+ local src = info.source
+ vm.cache.eachField[src] = cache
+ end)
+ for i = 1, #cache do
+ local res = callback(cache[i])
+ if res ~= nil then
+ return res
+ end
+ end
+end