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
|
---@class vm
local vm = require 'vm.vm'
local guide = require 'parser.guide'
---@class vm.runner
---@field loc parser.object
---@field mainBlock parser.object
---@field blocks table<parser.object, true>
---@field steps vm.runner.step[]
local mt = {}
mt.__index = mt
mt.index = 1
---@class parser.object
---@field _hasSorted boolean
---@class vm.runner.step
---@field type 'truly' | 'as' | 'object' | 'save' | 'load'
---@field pos integer
---@field node? vm.node
---@field object? parser.object
---@field ref? vm.runner.step
---@param filter parser.object
---@param pos integer
function mt:_compileNarrowByFilter(filter, pos)
if filter.type == 'unary' then
elseif filter.type == 'binary' then
else
if filter.type == 'getlocal' and filter.node == self.loc then
self.steps[#self.steps+1] = {
type = 'truly',
pos = pos,
}
end
end
end
function mt:_dropBlock(block)
local savePoint = {
type = 'save',
pos = block.start,
}
self.steps[#self.steps+1] = savePoint
self.steps[#self.steps+1] = {
type = 'load',
pos = block.finish,
ref = savePoint,
}
end
---@param block parser.object
function mt:_compileBlock(block)
if self.blocks[block] then
return
end
self.blocks[block] = true
if block == self.mainBlock then
return
end
local parentBlock = guide.getParentBlock(block)
self:_compileBlock(parentBlock)
if block.type == 'ifblock' then
if block[1] then
self:_compileNarrowByFilter(block.filter, block[1].start)
end
end
if block.type == 'if' then
self:_dropBlock(block)
end
if block.type == 'function' then
self:_dropBlock(block)
end
end
function mt:_preCompile()
for _, ref in ipairs(self.loc.ref) do
self.steps[#self.steps+1] = {
type = 'object',
object = ref,
pos = ref.start,
}
local block = guide.getParentBlock(ref)
self:_compileBlock(block)
end
table.sort(self.steps, function (a, b)
return a.pos < b.pos
end)
end
---@param callback fun(src: parser.object, node: vm.node)
function mt:launch(callback)
local node = vm.getNode(self.loc)
for _, step in ipairs(self.steps) do
if step.type == 'truly' then
node = node:copyTruly()
elseif step.type == 'as' then
elseif step.type == 'object' then
node = callback(step.object, node) or node
elseif step.type == 'save' then
-- Nothing need to do
elseif step.type == 'load' then
node = step.ref.node
end
step.node = node
end
end
---@param loc parser.object
---@return vm.runner
function vm.createRunner(loc)
local self = setmetatable({
loc = loc,
mainBlock = guide.getParentBlock(loc),
blocks = {},
steps = {},
}, mt)
self:_preCompile()
return self
end
|