diff options
Diffstat (limited to 'script/vm')
-rw-r--r-- | script/vm/compiler.lua | 54 | ||||
-rw-r--r-- | script/vm/global.lua | 38 | ||||
-rw-r--r-- | script/vm/node.lua | 2 | ||||
-rw-r--r-- | script/vm/tracer.lua | 76 |
4 files changed, 99 insertions, 71 deletions
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index b3052c60..dc81e836 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -67,6 +67,9 @@ local function searchFieldByLocalID(source, key, pushResult) if key then if source.type == 'variable' then ---@cast source vm.variable + if type(key) ~= 'string' then + return + end fields = source:getSets(key) else ---@cast source parser.object @@ -728,13 +731,13 @@ function vm.selectNode(list, index) local result if exp.type == 'call' then result = getReturn(exp.node, index, exp.args) - if not result:isTyped() then + if result:isEmpty() then result:merge(vm.declareGlobal('type', 'unknown')) end else ---@type vm.node result = vm.compileNode(exp) - if not result:isTyped() then + if result:isEmpty() then result:merge(vm.declareGlobal('type', 'unknown')) end end @@ -1233,6 +1236,9 @@ local compilerSwitch = util.switch() : case 'getmethod' : case 'getindex' : call(function (source) + if bindDocs(source) then + return + end if guide.isGet(source) and bindAs(source) then return end @@ -1257,18 +1263,28 @@ local compilerSwitch = util.switch() ---@cast k vm.global vm.compileByParentNode(source.node, k, function (src) vm.setNode(source, vm.compileNode(src)) - if src.value then - vm.setNode(source, vm.compileNode(src.value)) - end end) end end else if guide.isGet(source) then - local node = vm.traceNode(source) - if node then - vm.setNode(source, node) - return + --local node = vm.traceNode(source) + --if node then + -- vm.setNode(source, node) + --end + ---@cast key string + vm.compileByParentNode(source.node, key, function (src) + vm.setNode(source, vm.compileNode(src)) + end) + else + local hasDefinedField + ---@cast key string + vm.compileByParentNode(source.node, key, function (src) + hasDefinedField = true + vm.setNode(source, vm.compileNode(src)) + end) + if not hasDefinedField and source.value then + vm.setNode(source, vm.compileNode(source.value)) end end end @@ -1767,26 +1783,6 @@ local compilerSwitch = util.switch() vm.setNode(variable, vm.compileNode(variable.base)) return end - local parentVariable = variable:getParent() - local fieldName = variable:getFieldName() - if not parentVariable or not fieldName then - return - end - vm.compileByParentNode(parentVariable, fieldName, function (src) - if src.value then - if bindDocs(src) then - vm.setNode(variable, vm.compileNode(src)) - elseif src.value.type ~= 'nil' then - vm.setNode(variable, vm.compileNode(src.value)) - local node = vm.getNode(src) - if node then - vm.setNode(variable, node) - end - end - else - vm.setNode(variable, vm.compileNode(src)) - end - end) end) ---@param source parser.object diff --git a/script/vm/global.lua b/script/vm/global.lua index 066dfab9..5ffcdb34 100644 --- a/script/vm/global.lua +++ b/script/vm/global.lua @@ -4,6 +4,11 @@ local guide = require 'parser.guide' ---@class vm local vm = require 'vm.vm' +---@type table<string, vm.global> +local allGlobals = {} +---@type table<uri, table<string, boolean>> +local globalSubs = util.multiTable(2) + ---@class parser.object ---@field package _globalBase parser.object ---@field package _globalBaseMap table<string, parser.object> @@ -114,11 +119,39 @@ function mt:getKeyName() return self.name:match('[^' .. vm.ID_SPLITE .. ']+$') end +---@return string? +function mt:getFieldName() + return self.name:match(vm.ID_SPLITE .. '(.-)$') +end + ---@return boolean function mt:isAlive() return next(self.links) ~= nil end +---@param uri uri +---@return parser.object? +function mt:getParentBase(uri) + local parentID = self.name:match('^(.-)' .. vm.ID_SPLITE) + if not parentID then + return nil + end + local parentName = self.cate .. '|' .. parentID + local global = allGlobals[parentName] + if not global then + return nil + end + local link = global.links[uri] + if not link then + return nil + end + local luckyBoy = link.sets[1] or link.gets[1] + if not luckyBoy then + return nil + end + return vm.getGlobalBase(luckyBoy) +end + ---@param cate vm.global.cate ---@return vm.global local function createGlobal(name, cate) @@ -138,11 +171,6 @@ end ---@field package _globalNode vm.global|false ---@field package _enums? parser.object[] ----@type table<string, vm.global> -local allGlobals = {} ----@type table<uri, table<string, boolean>> -local globalSubs = util.multiTable(2) - local compileObject local compilerGlobalSwitch = util.switch() : case 'local' diff --git a/script/vm/node.lua b/script/vm/node.lua index f6d86949..cec0a36f 100644 --- a/script/vm/node.lua +++ b/script/vm/node.lua @@ -61,7 +61,7 @@ end ---@return boolean function mt:isTyped() for _, c in ipairs(self) do - if c.type == 'global' and c.cate == 'variable' then + if c.type == 'global' and c.cate == 'type' then return true end if guide.isLiteral(c) then diff --git a/script/vm/tracer.lua b/script/vm/tracer.lua index 1ec29a1e..de787625 100644 --- a/script/vm/tracer.lua +++ b/script/vm/tracer.lua @@ -12,9 +12,8 @@ local util = require 'utility' ---@class vm.tracer ---@field mode tracer.mode ---@field name string ----@field source parser.object ----@field variable vm.variable ----@field assigns parser.object[] +---@field source parser.object | vm.variable +---@field assigns (parser.object | vm.variable)[] ---@field assignMap table<parser.object, true> ---@field getMap table<parser.object, true> ---@field careMap table<parser.object, true> @@ -30,7 +29,7 @@ mt.fastCalc = true ---@return parser.object[] function mt:getCasts() - local root = guide.getRoot(self.source) + local root = guide.getRoot(self.main) if not root._casts then root._casts = {} local docs = root.docs @@ -92,12 +91,16 @@ function mt:collectCare(obj) end function mt:collectLocal() - local startPos = self.source.start + local startPos = self.source.base.start local finishPos = 0 - local variable = self.variable + local variable = self.source - assert(variable) + if variable.base.type ~= 'local' + and variable.base.type ~= 'self' then + self.assigns[#self.assigns+1] = variable + self.assignMap[self.source] = true + end for _, set in ipairs(variable.sets) do self.assigns[#self.assigns+1] = set @@ -121,7 +124,7 @@ function mt:collectLocal() if cast.name[1] == self.name and cast.start > startPos and cast.finish < finishPos - and vm.getCastTargetHead(cast) == self.source then + and vm.getCastTargetHead(cast) == variable.base then self.casts[#self.casts+1] = cast end end @@ -129,10 +132,6 @@ function mt:collectLocal() if #self.casts > 0 then self.fastCalc = false end - - if variable ~= vm.getVariable(self.source) then - self.fastCalc = false - end end function mt:collectGlobal() @@ -173,17 +172,20 @@ end ---@param finish integer ---@return parser.object? function mt:getLastAssign(start, finish) - local assign - for _, obj in ipairs(self.assigns) do - if obj.type == 'local' - or obj.type == 'self' then - assign = obj - break + local lastAssign + for _, assign in ipairs(self.assigns) do + local obj + if assign.type == 'variable' then + ---@cast assign vm.variable + obj = assign.base + else + ---@cast assign parser.object + obj = assign end if obj.start < start then goto CONTINUE end - if (obj.range or obj.start) >= finish then + if (obj.effect or obj.range or obj.start) >= finish then break end local objBlock = guide.getTopBlock(obj) @@ -192,11 +194,11 @@ function mt:getLastAssign(start, finish) end if objBlock.start <= finish and objBlock.finish >= finish then - assign = obj + lastAssign = obj end ::CONTINUE:: end - return assign + return lastAssign end ---@param pos integer @@ -656,9 +658,7 @@ local lookIntoChild = util.switch() and call.type == 'call' and call.node.special == 'type' and call.args - and call.args[1] - and call.args[1].type == 'getlocal' - and call.args[1].node == tracer.source then + and tracer.getMap[call.args[1]] then if action.op.type == '==' then topNode:narrow(tracer.uri, checker[1]) if outNode then @@ -790,23 +790,28 @@ end ---@field package _tracer vm.tracer ---@param mode tracer.mode ----@param source parser.object +---@param source parser.object | vm.variable ---@param name string ----@param variable vm.variable? ---@return vm.tracer? -local function createTracer(mode, source, name, variable) - local node = vm.compileNode(variable or source) +local function createTracer(mode, source, name) + local node = vm.compileNode(source) local tracer = node._tracer if tracer then return tracer end - local main = guide.getParentBlock(source) + local main + if source.type == 'variable' then + ---@cast source vm.variable + main = guide.getParentBlock(source.base) + else + ---@cast source parser.object + main = guide.getParentBlock(source) + end if not main then return nil end tracer = setmetatable({ source = source, - variable = variable, mode = mode, name = name, assigns = {}, @@ -833,7 +838,7 @@ end ---@param source parser.object ---@return vm.node? function vm.traceNode(source) - local mode, base, name, variable + local mode, base, name if vm.getGlobalNode(source) then base = vm.getGlobalBase(source) if not base then @@ -842,15 +847,14 @@ function vm.traceNode(source) mode = 'global' name = base.global:getCodeName() else - variable = vm.getVariable(source) - if not variable then + base = vm.getVariable(source) + if not base then return nil end - base = variable:getBase() - name = variable:getCodeName() + name = base:getCodeName() mode = 'local' end - local tracer = createTracer(mode, base, name, variable) + local tracer = createTracer(mode, base, name) if not tracer then return nil end |