summaryrefslogtreecommitdiff
path: root/script/core/generic.lua
blob: fe24bcfc0bbbc9e0a26ddfc65521962d43b3ced9 (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
142
143
144
145
146
147
local linker = require "core.linker"
---@class generic.value
---@field type string
---@field closure generic.closure
---@field proto parser.guide.object
---@field parent parser.guide.object

---@class generic.closure
---@field type string
---@field proto parser.guide.object
---@field upvalues table<string, generic.value[]>
---@field params generic.value[]
---@field returns generic.value[]

local m = {}

---@param closure generic.closure
---@param proto parser.guide.object
local function instantValue(closure, proto)
    ---@type generic.value
    local value = {
        type    = 'generic.value',
        closure = closure,
        proto   = proto,
        parent  = proto.parent,
    }
    return value
end

---递归实例化对象
---@param obj parser.guide.object
---@return generic.value
local function createValue(closure, obj, callback, road)
    if callback then
        road = road or {}
    end
    if obj.type == 'doc.type' then
        local types = {}
        local hasGeneric
        for i, tp in ipairs(obj.types) do
            local genericValue = createValue(closure, tp, callback, road)
            if genericValue then
                hasGeneric = true
                types[i] = genericValue
            else
                types[i] = tp
            end
        end
        if not hasGeneric then
            return nil
        end
        local value = instantValue(closure, obj)
        value.types = types
        linker.compileLink(value)
        return value
    end
    if obj.type == 'doc.type.name' then
        if not obj.typeGeneric then
            return nil
        end
        local key = obj[1]
        local value = instantValue(closure, obj)
        if callback then
            callback(road, key, obj)
        end
        linker.compileLink(value)
        return value
    end
end

-- 为所有的 param 与 return 创建副本
---@param closure generic.closure
local function buildValues(closure)
    local protoFunction = closure.proto
    local upvalues      = closure.upvalues
    local params        = closure.call.args
    if protoFunction.type == 'function' then
        for _, doc in ipairs(protoFunction.bindDocs) do
            if doc.type == 'doc.param' then
                local extends = doc.extends
                local index   = extends.paramIndex
                closure.params[index] = createValue(closure, extends, function (road, key, proto)
                    local param = params[index]
                    if not param then
                        return
                    end
                    local paramID
                    if proto.literal then
                        local str = param.type == 'string' and param[1]
                        if not str then
                            return
                        end
                        paramID = 'dn:' .. str
                    else
                        paramID = linker.getID(param)
                    end
                    if not paramID then
                        return
                    end
                    if not upvalues[key] then
                        upvalues[key] = {}
                    end
                    -- TODO
                    upvalues[key][#upvalues[key]+1] = paramID
                end)
            end
        end
        for _, doc in ipairs(protoFunction.bindDocs) do
            if doc.type == 'doc.return' then
                for _, rtn in ipairs(doc.returns) do
                    closure.returns[rtn.returnIndex] = createValue(closure, rtn)
                end
            end
        end
    end
    if protoFunction.type == 'doc.function' then
        
    end
end

---创建一个闭包
---@param protoFunction parser.guide.object # 原型函数
---@param parentClosure? generic.closure
---@return generic.closure
function m.createClosure(protoFunction, call, parentClosure)
    ---@type generic.closure
    local closure = {
        type     = 'generic.closure',
        parent   = protoFunction.parent,
        proto    = protoFunction,
        call     = call,
        upvalues = parentClosure and parentClosure.upvalues or {},
        params   = {},
        returns  = {},
    }
    buildValues(closure)

    if #closure.returns == 0 then
        return nil
    end

    linker.compileLink(closure)

    return closure
end

return m