summaryrefslogtreecommitdiff
path: root/server/src/core/implementation.lua
blob: d3681652b08e4eb80efa01e99d02ab022d45d6dc (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
local function findFieldBySource(positions, source, obj, result)
    if source.type == 'name' and source[1] == result.key then
        if obj.type == 'field' then
            for _, info in ipairs(obj) do
                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, obj in pairs(vm.results.sources) do
        if source.type == 'multi-source' then
            for i = 1, #obj do
                findFieldBySource(positions, source, obj[i], result)
            end
        else
            findFieldBySource(positions, source, obj, result)
        end
    end
end

local function parseResultAcrossUri(positions, vm, result)
    -- 跨越文件时,遍历的是值的绑定信息
    for _, info in ipairs(result.value) do
        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
        for _, info in ipairs(result.value) do
            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 parseResult(vm, result, lsp)
    local positions = {}
    local tp = result.type
    if     tp == 'local' then
        if result.value.lib then
            return positions
        end
        if result.value.uri ~= vm.uri then
            parseResultAcrossUri(positions, vm, result)
        else
            for _, info in ipairs(result) do
                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
            for _, info in ipairs(result) do
                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
        for _, info in ipairs(result) do
            if info.type == 'set' then
                positions[#positions+1] = {
                    info.source.start,
                    info.source.finish,
                }
            end
        end
    elseif tp == 'string' then
        -- require 'XXX' 专用
        positions[#positions+1] = {
            0,
            0,
            result.uri,
        }
    end
    return positions
end

return function (vm, result, lsp)
    if not result then
        return nil
    end
    local positions = parseResult(vm, result, lsp)
    return positions
end