244 lines
5.5 KiB
Lua
244 lines
5.5 KiB
Lua
local guide = require 'parser.guide'
|
|
---@class vm
|
|
local vm = require 'vm.vm'
|
|
|
|
---@param source parser.object?
|
|
---@return boolean|nil
|
|
function vm.testCondition(source)
|
|
if not source then
|
|
return nil
|
|
end
|
|
local node = vm.compileNode(source)
|
|
if node.optional then
|
|
return nil
|
|
end
|
|
local hasTrue, hasFalse
|
|
for n in node:eachObject() do
|
|
if n.type == 'boolean'
|
|
or n.type == 'doc.type.boolean' then
|
|
if n[1] == true then
|
|
hasTrue = true
|
|
end
|
|
if n[1] == false then
|
|
hasFalse = true
|
|
end
|
|
elseif n.type == 'global' and n.cate == 'type' then
|
|
if n.name == 'boolean'
|
|
or n.name == 'unknown' then
|
|
return nil
|
|
end
|
|
if n.name == 'false'
|
|
or n.name == 'nil' then
|
|
hasFalse = true
|
|
else
|
|
hasTrue = true
|
|
end
|
|
elseif n.type == 'nil' then
|
|
hasFalse = true
|
|
elseif guide.isLiteral(n) then
|
|
hasTrue = true
|
|
end
|
|
end
|
|
if hasTrue == hasFalse then
|
|
return nil
|
|
end
|
|
if hasTrue then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
---@param v vm.node.object
|
|
---@return string|false
|
|
local function getUnique(v)
|
|
if v.type == 'boolean' then
|
|
if v[1] == nil then
|
|
return false
|
|
end
|
|
return ('%s'):format(v[1])
|
|
end
|
|
if v.type == 'number' then
|
|
if not v[1] then
|
|
return false
|
|
end
|
|
return ('num:%s'):format(v[1])
|
|
end
|
|
if v.type == 'integer' then
|
|
if not v[1] then
|
|
return false
|
|
end
|
|
return ('num:%s'):format(v[1])
|
|
end
|
|
if v.type == 'table' then
|
|
---@cast v parser.object
|
|
return ('table:%s@%d'):format(guide.getUri(v), v.start)
|
|
end
|
|
if v.type == 'function' then
|
|
---@cast v parser.object
|
|
return ('func:%s@%d'):format(guide.getUri(v), v.start)
|
|
end
|
|
return false
|
|
end
|
|
|
|
---@param a parser.object?
|
|
---@param b parser.object?
|
|
---@return boolean|nil
|
|
function vm.equal(a, b)
|
|
if not a or not b then
|
|
return false
|
|
end
|
|
local nodeA = vm.compileNode(a)
|
|
local nodeB = vm.compileNode(b)
|
|
local mapA = {}
|
|
for obj in nodeA:eachObject() do
|
|
local unique = getUnique(obj)
|
|
if not unique then
|
|
return nil
|
|
end
|
|
mapA[unique] = true
|
|
end
|
|
for obj in nodeB:eachObject() do
|
|
local unique = getUnique(obj)
|
|
if not unique then
|
|
return nil
|
|
end
|
|
if not mapA[unique] then
|
|
return false
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
---@param v vm.object?
|
|
---@return integer?
|
|
function vm.getInteger(v)
|
|
if not v then
|
|
return nil
|
|
end
|
|
local node = vm.compileNode(v)
|
|
local result
|
|
for n in node:eachObject() do
|
|
if n.type == 'integer' then
|
|
if result then
|
|
return nil
|
|
else
|
|
result = n[1]
|
|
end
|
|
elseif n.type == 'number' then
|
|
if result then
|
|
return nil
|
|
elseif not math.tointeger(n[1]) then
|
|
return nil
|
|
else
|
|
result = math.tointeger(n[1])
|
|
end
|
|
elseif n.type ~= 'local'
|
|
and n.type ~= 'global' then
|
|
return nil
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
---@param v vm.object?
|
|
---@return string?
|
|
function vm.getString(v)
|
|
if not v then
|
|
return nil
|
|
end
|
|
local node = vm.compileNode(v)
|
|
local result
|
|
for n in node:eachObject() do
|
|
if n.type == 'string' then
|
|
if result then
|
|
return nil
|
|
else
|
|
result = n[1]
|
|
end
|
|
elseif n.type ~= 'local'
|
|
and n.type ~= 'global' then
|
|
return nil
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
---@param v vm.object?
|
|
---@return number?
|
|
function vm.getNumber(v)
|
|
if not v then
|
|
return nil
|
|
end
|
|
local node = vm.compileNode(v)
|
|
local result
|
|
for n in node:eachObject() do
|
|
if n.type == 'number'
|
|
or n.type == 'integer' then
|
|
if result then
|
|
return nil
|
|
else
|
|
result = n[1]
|
|
end
|
|
elseif n.type ~= 'local'
|
|
and n.type ~= 'global' then
|
|
return nil
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
---@param v vm.object
|
|
---@return boolean|nil
|
|
function vm.getBoolean(v)
|
|
if not v then
|
|
return nil
|
|
end
|
|
local node = vm.compileNode(v)
|
|
local result
|
|
for n in node:eachObject() do
|
|
if n.type == 'boolean' then
|
|
if result then
|
|
return nil
|
|
else
|
|
result = n[1]
|
|
end
|
|
elseif n.type ~= 'local'
|
|
and n.type ~= 'global' then
|
|
return nil
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
---@param v vm.object
|
|
---@return table<any, boolean>?
|
|
function vm.getLiterals(v)
|
|
if not v then
|
|
return nil
|
|
end
|
|
local map
|
|
local node = vm.compileNode(v)
|
|
for n in node:eachObject() do
|
|
local literal
|
|
if n.type == 'boolean'
|
|
or n.type == 'string'
|
|
or n.type == 'number'
|
|
or n.type == 'integer' then
|
|
literal = n[1]
|
|
end
|
|
if n.type == 'doc.type.string'
|
|
or n.type == 'doc.type.integer'
|
|
or n.type == 'doc.type.boolean' then
|
|
literal = n[1]
|
|
end
|
|
if literal ~= nil then
|
|
if not map then
|
|
map = {}
|
|
end
|
|
map[literal] = true
|
|
end
|
|
end
|
|
return map
|
|
end
|