summaryrefslogtreecommitdiff
path: root/server/src/core/implementation.lua
blob: b7ca2c6efe4ba56633279794d9679aa33fb65ffc (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
148
149
150
151
152
153
154
local function parseValueSimily(vm, source, lsp)
    local key = source[1]
    if not key then
        return nil
    end
    local positions = {}
    for _, other in ipairs(vm.sources) do
        if other == source then
            goto CONTINUE
        end
        if      other[1] == key
            and not other:bindLocal()
            and other:bindValue()
            and other:action() == 'set'
            and source:bindValue() ~= other:bindValue()
        then
            positions[#positions+1] = {
                other.start,
                other.finish,
            }
        end
        :: CONTINUE ::
    end
    if #positions == 0 then
        return nil
    end
    return positions
end

local function parseValueCrossFile(vm, source, lsp)
    local value = source:bindValue()
    local positions = {}
    value:eachInfo(function (info)
        if info.type == 'local' and info.source.uri == value.uri then
            positions[#positions+1] = {
                info.source.start,
                info.source.finish,
                value.uri,
            }
            return true
        end
    end)
    if #positions > 0 then
        return positions
    end

    value:eachInfo(function (info)
        if info.type == 'set' and info.source.uri == value.uri  then
            positions[#positions+1] = {
                info.source.start,
                info.source.finish,
                value.uri,
            }
        end
    end)
    if #positions > 0 then
        return positions
    end

    value:eachInfo(function (info)
        if info.type == 'return' and info.source.uri == value.uri then
            positions[#positions+1] = {
                info.source.start,
                info.source.finish,
                value.uri,
            }
        end
    end)
    if #positions > 0 then
        return positions
    end

    local destVM = lsp:getVM(value.uri)
    if not destVM then
        positions[#positions+1] = {
            0, 0, value.uri,
        }
        return positions
    end

    local result = parseValueSimily(destVM, source, lsp)
    if result then
        for _, position in ipairs(result) do
            positions[#positions+1] = position
            position[3] = value.uri
        end
    end
    if #positions > 0 then
        return positions
    end

    return positions
end

local function parseValue(vm, source, lsp)
    local value = source:bindValue()
    if value.uri ~= vm.uri then
        return parseValueCrossFile(vm, source, lsp)
    end
    local positions = {}
    value:eachInfo(function (info)
        if info.type == 'set' then
            positions[#positions+1] = {
                info.source.start,
                info.source.finish,
            }
        end
    end)
    if #positions == 0 then
        return nil
    end
    return positions
end

local function parseLabel(vm, label, lsp)
    local positions = {}
    label:eachInfo(function (info)
        if info.type == 'set' then
            positions[#positions+1] = {
                info.source.start,
                info.source.finish,
            }
        end
    end)
    if #positions == 0 then
        return nil
    end
    return positions
end

local function jumpUri(vm, source, lsp)
    local uri = source:get 'target uri'
    local positions = {}
    positions[#positions+1] = {
        0, 0, uri,
    }
    return positions
end

return function (vm, source, lsp)
    if not source then
        return nil
    end
    if source:bindValue() then
        return parseValue(vm, source, lsp)
            or parseValueSimily(vm, source, lsp)
    end
    if source:bindLabel() then
        return parseLabel(vm, source:bindLabel(), lsp)
    end
    if source:get 'target uri' then
        return jumpUri(vm, source, lsp)
    end
end