summaryrefslogtreecommitdiff
path: root/server/src/core/implementation.lua
blob: 8e42556aed7044d235c7f523e2877bd2e1cb77ad (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
local function findFieldBySource(positions, source, vm, result)
    if source.type == 'name' and source[1] == result.key then
        local obj = source.bind
        if obj.type == 'field' then
            vm:eachInfo(obj, function (info)
                if info.type == 'set' and info.source == source then
                    positions[#positions+1] = {
                        source.start,
                        source.finish,
                        source.uri,
                    }
                end
            end)
        end
    end
end

local function findFieldByName(positions, vm, result)
    for _, source in pairs(vm.results.sources) do
        findFieldBySource(positions, source, vm, result)
    end
end


local function parseResultAcrossUri(positions, vm, result)
    -- 跨越文件时,遍历的是值的绑定信息
    result.value:eachInfo(function (info)
        if info.type == 'set' and info.source.uri == result.value.uri then
            positions[1] = {
                info.source.start,
                info.source.finish,
                info.source.uri,
            }
        end
    end)
    if #positions == 0 then
        result.value:eachInfo(function (info)
            if info.type == 'return' and info.source.uri == result.value.uri then
                positions[1] = {
                    info.source.start,
                    info.source.finish,
                    info.source.uri,
                }
            end
        end)
    end
    if #positions == 0 then
        positions[1] = {
            0, 0,
            result.value.uri,
        }
    end
end

local function findFieldCrossUriByName(positions, vm, result, lsp)
    if not lsp then
        return
    end
    local parentValue = result.parentValue
    if not parentValue then
        return
    end
    if parentValue.uri ~= vm.uri then
        local destVM = lsp:loadVM(parentValue.uri)
        if destVM then
            findFieldByName(positions, destVM, result)
        end
    end
end

local function parseResultAsVar(vm, result, lsp)
    local positions = {}
    local tp = result.type
    if     tp == 'local' then
        if result.link then
            result = result.link
        end
        if result.value.lib then
            return positions
        end
        if result.value.uri ~= vm.uri then
            parseResultAcrossUri(positions, vm, result)
        else
            vm:eachInfo(result, function (info)
                if info.type == 'set' then
                    positions[#positions+1] = {
                        info.source.start,
                        info.source.finish,
                        info.source.uri,
                    }
                end
            end)
        end
    elseif tp == 'field' then
        if result.value.lib then
            return positions
        end
        if result.value.uri ~= vm.uri then
            parseResultAcrossUri(positions, vm, result)
        else
            vm:eachInfo(result, function (info)
                if info.type == 'set' then
                    positions[#positions+1] = {
                        info.source.start,
                        info.source.finish,
                        info.source.uri,
                    }
                end
            end)
            if #positions == 0 then
                findFieldByName(positions, vm, result)
                findFieldCrossUriByName(positions, vm, result, lsp)
            end
        end
    elseif tp == 'label' then
        vm:eachInfo(result, function (info)
            if info.type == 'set' then
                positions[#positions+1] = {
                    info.source.start,
                    info.source.finish,
                }
            end
        end)
    end
    return positions
end

local function parseResultAsValue(vm, value, lsp)
    local tp = value:getType()
    local positions = {}
    if tp == 'string' then
        -- require 'XXX' 专用
        positions[#positions+1] = {
            0,
            0,
            value.uri,
        }
    end
    return positions
end

return function (vm, result, lsp)
    if not result then
        return nil
    end
    if result.type == 'value' then
        return parseResultAsValue(vm, result, lsp)
    else
        return parseResultAsVar(vm, result, lsp)
    end
end