summaryrefslogtreecommitdiff
path: root/server/src/vm/library.lua
blob: 258118a78e49d2c4f34865cc4da073df1126bb7b (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
local sourceMgr = require 'vm.source'

local valueMgr
local functionMgr

local CHILD_CACHE = {}
local VALUE_CACHE = {}
local Special = {}

local buildLibValue
local buildLibChild

function buildLibValue(lib)
    if VALUE_CACHE[lib] then
        return VALUE_CACHE[lib]
    end
    if not valueMgr then
        valueMgr = require 'vm.value'
        functionMgr = require 'vm.function'
    end
    local tp = lib.type
    local value
    if     tp == 'table' then
        value = valueMgr.create('table', sourceMgr.dummy())
    elseif tp == 'function' then
        local dummySource = sourceMgr.dummy()
        value = valueMgr.create('function', dummySource)
        local func = functionMgr.create(dummySource)
        value:setFunction(func)
        if lib.args then
            for _, arg in ipairs(lib.args) do
                func:createLibArg(arg, sourceMgr.dummy())
            end
        end
        if lib.returns then
            for i, rtn in ipairs(lib.returns) do
                if rtn.type == '...' then
                    func:returnDots(i)
                else
                    func:setReturn(i, buildLibValue(rtn))
                end
            end
            if lib.special == 'pairs' then
                func:setReturn(1, Special['next'])
            end
            if lib.special == 'ipairs' then
                func:setReturn(1, Special['@ipairs'])
            end
        end
    elseif tp == 'string' then
        value = valueMgr.create('string', sourceMgr.dummy())
    elseif tp == 'boolean' then
        value = valueMgr.create('boolean', sourceMgr.dummy())
    elseif tp == 'number' then
        value = valueMgr.create('number', sourceMgr.dummy())
    elseif tp == 'integer' then
        value = valueMgr.create('integer', sourceMgr.dummy())
    elseif tp == 'nil' then
        value = valueMgr.create('nil', sourceMgr.dummy())
    else
        value = valueMgr.create(tp or 'any', sourceMgr.dummy())
    end
    value:setLib(lib)
    VALUE_CACHE[lib] = value

    if lib.child then
        for fName, fLib in pairs(lib.child) do
            local fValue = buildLibValue(fLib)
            value:rawSet(fName, fValue)
            value:addInfo('set child', sourceMgr.dummy(), fName, fValue)
        end
    end

    if lib.special == 'next' then
        Special['next'] = value
    end
    if lib.special == '@ipairs' then
        Special['@ipairs'] = value
        return nil
    end

    return value
end

function buildLibChild(lib)
    if not valueMgr then
        valueMgr = require 'vm.value'
        functionMgr = require 'vm.function'
    end
    if CHILD_CACHE[lib] then
        return CHILD_CACHE[lib]
    end
    local child = {}
    for fName, fLib in pairs(lib.child) do
        local fValue = buildLibValue(fLib)
        child[fName] = fValue
    end
    CHILD_CACHE[lib] = child
    return child
end

local function clearCache()
    CHILD_CACHE = {}
    VALUE_CACHE = {}
end

return {
    value = buildLibValue,
    child = buildLibChild,
    clear = clearCache,
}