summaryrefslogtreecommitdiff
path: root/script/vm/generic.lua
blob: 28caa2db2e28146ab8bfce0b318750dbe93129fe (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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
local nodeMgr = require 'vm.node'

---@class parser.object
---@field _generic vm.generic

---@class vm.generic
---@field sign  vm.sign
---@field proto vm.node
local mt = {}
mt.__index = mt
mt.type = 'generic'

---@param node      vm.node
---@param resolved? table<string, vm.node>
---@return vm.node
local function cloneObject(node, resolved)
    if not resolved then
        return node
    end
    if node.type == 'doc.generic.name' then
        local key = node[1]
        return resolved[key] or node
    end
    if node.type == 'doc.type' then
        local newType = {
            type   = node.type,
            start  = node.start,
            finish = node.finish,
            parent = node.parent,
            types  = {},
        }
        for i, typeUnit in ipairs(node.types) do
            local newObj     = cloneObject(typeUnit, resolved)
            newObj.parent    = newType
            newType.types[i] = newObj
        end
        return newType
    end
    if node.type == 'doc.type.arg' then
        local newArg = {
            type    = node.type,
            start   = node.start,
            finish  = node.finish,
            parent  = node.parent,
            name    = node.name,
            extends = cloneObject(node.extends, resolved)
        }
        newArg.name.parent    = newArg
        newArg.extends.parent = newArg
        return newArg
    end
    if node.type == 'doc.type.array' then
        local newArray = {
            type   = node.type,
            start  = node.start,
            finish = node.finish,
            parent = node.parent,
            node   = cloneObject(node.node, resolved),
        }
        newArray.node.parent = newArray
        return newArray
    end
    if node.type == 'doc.type.table' then
        local newTable = {
            type   = node.type,
            start  = node.start,
            finish = node.finish,
            parent = node.parent,
            fields = {},
        }
        for i, field in ipairs(node.fields) do
            local newField = {
                type    = field.type,
                start   = field.start,
                finish  = field.finish,
                parent  = newTable,
                name    = cloneObject(field.name, resolved),
                extends = cloneObject(field.extends, resolved),
            }
            newField.name.parent    = newField
            newField.extends.parent = newField
            newTable.fields[i] = newField
        end
        return newTable
    end
    if node.type == 'doc.type.function' then
        local newDocFunc = {
            type    = node.type,
            start   = node.start,
            finish  = node.finish,
            parent  = node.parent,
            args    = {},
            returns = {},
        }
        for i, arg in ipairs(node.args) do
            local newObj       = cloneObject(arg, resolved)
            newObj.parent      = newDocFunc
            newObj.optional    = arg.optional
            newDocFunc.args[i] = newObj
        end
        for i, ret in ipairs(node.returns) do
            local newObj          = cloneObject(ret, resolved)
            newObj.parent         = newDocFunc
            newObj.optional       = ret.optional
            newDocFunc.returns[i] = cloneObject(ret, resolved)
        end
        return newDocFunc
    end
    return node
end

---@param argNodes vm.node[]
---@return parser.object
function mt:resolve(argNodes)
    local resolved = self.sign:resolve(argNodes)
    local newProto = cloneObject(self.proto, resolved)
    return newProto
end

function mt:eachNode()
    local nodes = {}
    for n in nodeMgr.eachNode(self.proto) do
        nodes[#nodes+1] = n
    end
    local i = 0
    return function ()
        i = i + 1
        return nodes[i], self
    end
end

---@param proto vm.node
---@param sign  vm.sign
return function (proto, sign)
    local compiler = require 'vm.compiler'
    local generic = setmetatable({
        sign  = sign,
        proto = compiler.compileNode(proto),
    }, mt)
    return generic
end