summaryrefslogtreecommitdiff
path: root/script-beta/core/hover/arg.lua
blob: 2b7d47d3c9373dda72242ac8f0eb6e737951e80e (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
local guide = require 'parser.guide'
local vm    = require 'vm'

local function mergeTypesInLibrary(types)
    if type(types) == 'table' then
        return table.concat(types, '|')
    else
        return types or 'any'
    end
end

local function asLibrary(source, oop)
    if not source.args then
        return ''
    end
    local start = 1
    local methodDef
    local parent = source.parent
    if parent and parent.type == 'setmethod' then
        methodDef = true
    end
    if not methodDef and oop then
        start = 2
    end
    local args = {}
    local afterCount = 0
    for i = start, #source.args do
        local buf = {}
        local arg = source.args[i]
        local name = arg.name
        if arg.optional then
            if i == start then
                buf[#buf+1] = '['
            else
                buf[#buf+1] = ' ['
            end
        end
        if i > start then
            buf[#buf+1] = ', '
        end
        if name then
            buf[#buf+1] = ('%s: %s'):format(name, mergeTypesInLibrary(arg.type))
        else
            buf[#buf+1] = ('%s'):format(mergeTypesInLibrary(arg.type))
        end
        if arg.optional == 'after' then
            afterCount = afterCount + 1
        elseif arg.optional == 'self' then
            buf[#buf+1] = ']'
        end
        if i == #source.args and afterCount > 0 then
            buf[#buf+1] = (']'):rep(afterCount)
        end
        args[#args+1] = table.concat(buf)
    end
    return table.concat(args)
end

local function optionalArg(arg)
    if not arg.bindDocs then
        return false
    end
    local name = arg[1]
    for _, doc in ipairs(arg.bindDocs) do
        if doc.type == 'doc.param' and doc.param[1] == name then
            return doc.optional
        end
    end
end

local function asFunction(source, oop)
    if not source.args then
        return ''
    end
    local args = {}
    for i = 1, #source.args do
        local arg = source.args[i]
        local name = arg.name or guide.getName(arg)
        if name then
            args[i] = ('%s: %s%s'):format(
                name,
                vm.getInferType(arg),
                optionalArg(arg) and '?' or ''
            )
        else
            args[i] = ('%s'):format(vm.getInferType(arg))
        end
    end
    local methodDef
    local parent = source.parent
    if parent and parent.type == 'setmethod' then
        methodDef = true
    end
    if not methodDef and oop then
        return table.concat(args, ', ', 2)
    else
        return table.concat(args, ', ')
    end
end

local function asDocFunction(source)
    if not source.args then
        return ''
    end
    local args = {}
    for i = 1, #source.args do
        local arg = source.args[i]
        local name = arg.name[1]
        args[i] = ('%s: %s%s'):format(
            name,
            vm.getInferType(arg.extends),
            arg.optional and '?' or ''
        )
    end
    return table.concat(args, ', ')
end

return function (source, oop)
    if source.type == 'library' then
        return asLibrary(source.value, oop)
    elseif source.library then
        return asLibrary(source, oop)
    end
    if source.type == 'function' then
        return asFunction(source, oop)
    end
    if source.type == 'doc.type.function' then
        return asDocFunction(source)
    end
    return ''
end