summaryrefslogtreecommitdiff
path: root/script/vm
diff options
context:
space:
mode:
Diffstat (limited to 'script/vm')
-rw-r--r--script/vm/compiler.lua54
-rw-r--r--script/vm/global.lua38
-rw-r--r--script/vm/node.lua2
-rw-r--r--script/vm/tracer.lua76
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