summaryrefslogtreecommitdiff
path: root/script/vm/generic.lua
blob: e0096e3011e5c38d1e2f14b854e6353703e848bc (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
local nodeMgr = require 'vm.node'

---@class vm.node.generic
---@field parent vm.node.generic-manager
---@field node   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
            newDocFunc.args[i] = newObj
        end
        for i, ret in ipairs(node.returns) do
            local newObj          = cloneObject(ret, resolved)
            newObj.parent         = newDocFunc
            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.parent:resolve(argNodes)
    local newProto = cloneObject(self.node, resolved)
    return newProto
end

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

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