summaryrefslogtreecommitdiff
path: root/script/vm/runner.lua
blob: d082538944a5e5ddadbbc7f0d3fb6971db3e1a34 (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
---@class vm
local vm    = require 'vm.vm'
local guide = require 'parser.guide'

---@class vm.local-compiler
---@field loc       parser.object
---@field mainBlock parser.object
---@field blocks    table<parser.object, table>
local mt = {}
mt.__index = mt
mt.index = 1


---@class parser.object
---@field _hasSorted      boolean

---@param source parser.object
local function sortRefs(source)
    if source._hasSorted then
        return
    end
    source._hasSorted = true
    table.sort(source.ref, function (a, b)
        return (a.range or a.start) < (b.range or b.start)
    end)
end

---@param node  vm.node
---@param block parser.object
---@return vm.node
function mt:_compileBlock(node, block)
    for _ = 1, 10000 do
        if self.blocks[block]
        or self.mainBlock == block
        or block.type == 'function'
        or block.type == 'main' then
            return node
        end
        self.blocks[block] = {}
        block = guide.getParentBlock(block)
    end
    error('compile block overstack')
end

---@param node        vm.node
---@param currentBlock parser.object
---@param callback     fun(src: parser.object, node: vm.node)
---@return vm.node
function mt:_runBlock(node, currentBlock, callback)
    local currentNode = self:_compileBlock(node, currentBlock)
    for _ = 1, 10000 do
        local ref = self.loc.ref[self.index]
        if not ref
        or ref.start > currentBlock.finish then
            return node
        end
        local block = guide.getParentBlock(ref)
        if block == currentBlock then
            callback(ref, currentNode)
            self.index = self.index + 1
            if ref.type == 'setlocal' then
                currentNode = vm.getNode(ref)
            end
        else
            currentNode = self:_runBlock(currentNode, block, callback)
        end
    end
    error('run block overstack')
end

---@param callback    fun(src: parser.object, node: vm.node)
function mt:launch(callback)
    self:_runBlock(vm.getNode(self.loc), self.mainBlock, callback)
end

---@param loc parser.object
---@return vm.local-compiler
function vm.createRunner(loc)
    local self = setmetatable({
        loc       = loc,
        mainBlock = guide.getParentBlock(loc),
        blocks    = {},
    }, mt)

    sortRefs(loc)

    return self
end