summaryrefslogtreecommitdiff
path: root/script/vm/type.lua
blob: 5bdc975b3134969f213321392cdc17e6b5dc67ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
local nodeMgr   = require 'vm.node'
local compiler  = require 'vm.compiler'
local globalMgr = require 'vm.global-manager'

---@class vm.type-manager
local m = {}

---@param child  vm.node
---@param parent vm.node
---@return boolean
function m.isSubType(child, parent, mark)
    if type(parent) == 'string' then
        parent = globalMgr.getGlobal('type', parent)
    end
    if type(child) == 'string' then
        child = globalMgr.getGlobal('type', child)
    end

    if parent.type == 'global' and parent.cate == 'type' and parent.name == 'any' then
        return true
    end

    if child.type == 'doc.type' then
        for _, typeUnit in ipairs(child.types) do
            if not m.isSubType(typeUnit, parent) then
                return false
            end
        end
        return true
    end

    if child.type == 'doc.type.name' then
        child = globalMgr.getGlobal('type', child[1])
    end

    if child.type == 'global' and child.cate == 'type' then
        if parent.type == 'doc.type' then
            for _, typeUnit in ipairs(parent.types) do
                if m.isSubType(child, typeUnit) then
                    return true
                end
            end
        end

        if parent.type == 'doc.type.name' then
            parent = globalMgr.getGlobal('type', parent[1])
        end

        if parent.type == 'global' and parent.cate == 'type' then
            if parent.name == child.name then
                return true
            end
            mark = mark or {}
            if mark[child.name] then
                return false
            end
            mark[child.name] = true
            for _, set in ipairs(child:getSets()) do
                if set.type == 'doc.class' and set.extends then
                    for _, ext in ipairs(set.extends) do
                        if m.isSubType(globalMgr.getGlobal('type', ext[1]), parent, mark) then
                            return true
                        end
                    end
                end
            end
        end
    end

    return false
end

---@param tnode vm.node
---@param knode vm.node
function m.getTableValue(tnode, knode)
    local result
    for tn in nodeMgr.eachNode(tnode) do
        if tn.type == 'doc.type.table' then
            for _, field in ipairs(tn.fields) do
                if m.isSubType(field.name, knode) then
                    result = nodeMgr.mergeNode(compiler.compileNode(field.extends), result)
                end
            end
        end
        if tn.type == 'doc.type.array' then
            if m.isSubType(globalMgr.getGlobal('type', 'integer'), knode) then
                result = nodeMgr.mergeNode(compiler.compileNode(tn.node), result)
            end
        end
    end
    return result
end

---@param tnode vm.node
---@param vnode vm.node
function m.getTableKey(tnode, vnode)
    local result
    for tn in nodeMgr.eachNode(tnode) do
        if tn.type == 'doc.type.table' then
            for _, field in ipairs(tn.fields) do
                if m.isSubType(field.extends, vnode) then
                    result = nodeMgr.mergeNode(compiler.compileNode(field.name), result)
                end
            end
        end
        if tn.type == 'doc.type.array' then
            if m.isSubType(tn.node, vnode) then
                result = nodeMgr.mergeNode(globalMgr.getGlobal('type', 'integer'), result)
            end
        end
    end
    return result
end

return m