Skip to content

Commit 86557f9

Browse files
committed
merge if results
1 parent e8c06f2 commit 86557f9

File tree

4 files changed

+224
-67
lines changed

4 files changed

+224
-67
lines changed

script/vm/compiler.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -978,12 +978,12 @@ local compilerSwitch = util.switch()
978978
if src.type == 'setlocal' then
979979
if src.value and guide.isLiteral(src.value) then
980980
if src.value.type == 'table' then
981-
vm.setNode(src, src.value)
981+
vm.setNode(src, vm.createNode(src.value), true)
982982
else
983-
vm.setNode(src, vm.compileNode(src.value))
983+
vm.setNode(src, vm.compileNode(src.value), true)
984984
end
985985
else
986-
vm.setNode(src, node)
986+
vm.setNode(src, node, true)
987987
end
988988
return vm.getNode(src)
989989
elseif src.type == 'getlocal' then

script/vm/node.lua

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -114,56 +114,98 @@ function mt:isNullable()
114114
end
115115

116116
---@return vm.node
117-
function mt:copyTruly()
118-
local newNode = vm.createNode()
119-
newNode.optional = false
120-
local hasBoolean, hasTrue
121-
for _, c in ipairs(self) do
117+
function mt:setTruly()
118+
if self.optional == true then
119+
self.optional = nil
120+
end
121+
local hasBoolean
122+
local index = 0
123+
while true do
124+
index = index + 1
125+
local c = self[index]
126+
if not c then
127+
break
128+
end
122129
if c.type == 'nil'
123130
or (c.type == 'boolean' and c[1] == false)
124131
or (c.type == 'doc.type.boolean' and c[1] == false) then
125-
goto CONTINUE
132+
table.remove(self, index)
133+
self[c] = nil
134+
index = index - 1
126135
end
127-
if c.type == 'global' and c.cate == 'type' and c.name == 'boolean' then
136+
if (c.type == 'global' and c.cate == 'type' and c.name == 'boolean')
137+
or (c.type == 'boolean' or c.type == 'doc.type.boolean') then
128138
hasBoolean = true
139+
table.remove(self, index)
140+
self[c] = nil
141+
index = index - 1
142+
end
143+
end
144+
if hasBoolean then
145+
self[#self+1] = {
146+
type = 'doc.type.boolean',
147+
[1] = true,
148+
}
149+
end
150+
end
151+
152+
---@return vm.node
153+
function mt:setFalsy()
154+
if self.optional == false then
155+
self.optional = nil
156+
end
157+
local hasBoolean
158+
local index = 0
159+
while true do
160+
index = index + 1
161+
local c = self[index]
162+
if not c then
163+
break
164+
end
165+
if c.type == 'nil'
166+
or (c.type == 'boolean' and c[1] == true)
167+
or (c.type == 'doc.type.boolean' and c[1] == true) then
129168
goto CONTINUE
130169
end
131-
if c.type == 'boolean' or c.type == 'doc.type.boolean' then
132-
hasTrue = true
170+
if (c.type == 'global' and c.cate == 'type' and c.name == 'boolean')
171+
or (c.type == 'boolean' or c.type == 'doc.type.boolean') then
172+
hasBoolean = true
173+
goto CONTINUE
133174
end
134-
newNode:merge(c)
175+
table.remove(self, index)
176+
self[c] = nil
177+
index = index - 1
135178
::CONTINUE::
136179
end
137-
if hasBoolean and not hasTrue then
138-
newNode:merge {
180+
if hasBoolean then
181+
self[#self+1] = {
139182
type = 'doc.type.boolean',
140-
[1] = true,
183+
[1] = false,
141184
}
142185
end
143-
return newNode
144186
end
145187

146188
---@param name string
147-
---@return vm.node
148-
function mt:copyWithout(name)
149-
local newNode = vm.createNode()
150-
if self:isOptional() then
151-
newNode:addOptional()
152-
end
153-
for _, c in ipairs(self) do
189+
function mt:remove(name)
190+
local index = 0
191+
while true do
192+
index = index + 1
193+
local c = self[index]
194+
if not c then
195+
break
196+
end
154197
if (c.type == 'global' and c.cate == 'type' and c.name == name)
155198
or (c.type == name)
156199
or (c.type == 'doc.type.integer' and (name == 'number' or name == 'integer'))
157200
or (c.type == 'doc.type.boolean' and name == 'boolean')
158201
or (c.type == 'doc.type.table' and name == 'table')
159202
or (c.type == 'doc.type.array' and name == 'table')
160203
or (c.type == 'doc.type.function' and name == 'function') then
161-
goto CONTINUE
204+
table.remove(self, index)
205+
self[c] = nil
206+
index = index - 1
162207
end
163-
newNode:merge(c)
164-
::CONTINUE::
165208
end
166-
return newNode
167209
end
168210

169211
---@return fun():vm.object

script/vm/runner.lua

Lines changed: 124 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,44 +16,61 @@ mt.index = 1
1616
---@field _hasSorted boolean
1717

1818
---@class vm.runner.step
19-
---@field type 'truly' | 'optional' | 'add' | 'remove' | 'object' | 'save' | 'load'
19+
---@field type 'truly' | 'falsy' | 'add' | 'remove' | 'object' | 'save' | 'load' | 'merge'
2020
---@field pos integer
21+
---@field order? integer
2122
---@field node? vm.node
2223
---@field object? parser.object
23-
---@field ref? vm.runner.step
2424
---@field name? string
25+
---@field copy? boolean
26+
---@field ref1? vm.runner.step
27+
---@field ref2? vm.runner.step
2528

2629
---@param filter parser.object
2730
---@param pos integer
2831
function mt:_compileNarrowByFilter(filter, pos)
2932
if not filter then
3033
return
3134
end
35+
if filter.type == 'paren' then
36+
if filter.exp then
37+
self:_compileNarrowByFilter(filter.exp, pos)
38+
end
39+
return
40+
end
3241
if filter.type == 'unary' then
42+
if filter.op and filter.op.type == 'not' then
43+
local exp = filter[1]
44+
if exp and exp.type == 'getlocal' and exp.node == self.loc then
45+
self.steps[#self.steps+1] = {
46+
type = 'truly',
47+
pos = pos,
48+
order = 2,
49+
}
50+
self.steps[#self.steps+1] = {
51+
type = 'falsy',
52+
pos = pos,
53+
order = 4,
54+
}
55+
end
56+
end
3357
elseif filter.type == 'binary' then
3458
else
3559
if filter.type == 'getlocal' and filter.node == self.loc then
3660
self.steps[#self.steps+1] = {
37-
type = 'truly',
38-
pos = pos,
61+
type = 'falsy',
62+
pos = pos,
63+
order = 2,
64+
}
65+
self.steps[#self.steps+1] = {
66+
type = 'truly',
67+
pos = pos,
68+
order = 4,
3969
}
4070
end
4171
end
4272
end
4373

44-
function mt:_dropBlock(block)
45-
local savePoint = {
46-
type = 'save',
47-
pos = block.start,
48-
}
49-
self.steps[#self.steps+1] = savePoint
50-
self.steps[#self.steps+1] = {
51-
type = 'load',
52-
pos = block.finish,
53-
ref = savePoint,
54-
}
55-
end
56-
5774
---@param block parser.object
5875
function mt:_compileBlock(block)
5976
if self.blocks[block] then
@@ -67,19 +84,82 @@ function mt:_compileBlock(block)
6784
local parentBlock = guide.getParentBlock(block)
6885
self:_compileBlock(parentBlock)
6986

70-
if block.type == 'ifblock'
71-
or block.type == 'elseif' then
72-
if block[1] then
73-
self:_compileNarrowByFilter(block.filter, block[1].start)
74-
end
75-
end
76-
7787
if block.type == 'if' then
78-
self:_dropBlock(block)
88+
---@type vm.runner.step[]
89+
local finals = {}
90+
for _, childBlock in ipairs(block) do
91+
if #childBlock > 0 then
92+
local initState = {
93+
type = 'save',
94+
copy = true,
95+
pos = childBlock.start,
96+
order = 1,
97+
}
98+
local outState = {
99+
type = 'save',
100+
copy = true,
101+
pos = childBlock.start,
102+
order = 2,
103+
}
104+
local filterState = {
105+
type = 'save',
106+
copy = true,
107+
pos = childBlock.start,
108+
order = 3,
109+
}
110+
self.steps[#self.steps+1] = initState
111+
self.steps[#self.steps+1] = outState
112+
self.steps[#self.steps+1] = filterState
113+
self.steps[#self.steps+1] = {
114+
type = 'load',
115+
ref1 = outState,
116+
pos = childBlock[1].start - 1,
117+
order = 1,
118+
}
119+
self.steps[#self.steps+1] = {
120+
type = 'load',
121+
ref1 = initState,
122+
pos = childBlock[1].start - 1,
123+
order = 3,
124+
}
125+
self:_compileNarrowByFilter(childBlock.filter, childBlock[1].start - 1)
126+
local finalState = {
127+
type = 'save',
128+
pos = childBlock.finish,
129+
order = 1,
130+
}
131+
finals[#finals+1] = finalState
132+
self.steps[#self.steps+1] = finalState
133+
self.steps[#self.steps+1] = {
134+
type = 'load',
135+
ref1 = outState,
136+
pos = childBlock.finish,
137+
order = 2,
138+
}
139+
end
140+
end
141+
for i, final in ipairs(finals) do
142+
self.steps[#self.steps+1] = {
143+
type = 'merge',
144+
ref1 = final,
145+
pos = block.finish,
146+
order = i,
147+
}
148+
end
79149
end
80150

81151
if block.type == 'function' then
82-
self:_dropBlock(block)
152+
local savePoint = {
153+
type = 'save',
154+
copy = true,
155+
pos = block.start,
156+
}
157+
self.steps[#self.steps+1] = savePoint
158+
self.steps[#self.steps+1] = {
159+
type = 'load',
160+
pos = block.finish,
161+
ref1 = savePoint,
162+
}
83163
end
84164
end
85165

@@ -94,28 +174,37 @@ function mt:_preCompile()
94174
self:_compileBlock(block)
95175
end
96176
table.sort(self.steps, function (a, b)
97-
return a.pos < b.pos
177+
if a.pos == b.pos then
178+
return (a.order or 0) < (b.order or 0)
179+
else
180+
return a.pos < b.pos
181+
end
98182
end)
99183
end
100184

101185
---@param callback fun(src: parser.object, node: vm.node)
102186
function mt:launch(callback)
103-
local node = vm.getNode(self.loc)
187+
local node = vm.getNode(self.loc):copy()
104188
for _, step in ipairs(self.steps) do
189+
if step.copy then
190+
node = node:copy()
191+
end
105192
if step.type == 'truly' then
106-
node = node:copyTruly()
107-
elseif step.type == 'optional' then
108-
node = node:copy():addOptional()
193+
node:setTruly()
194+
elseif step.type == 'falsy' then
195+
node:setFalsy()
109196
elseif step.type == 'add' then
110-
node = node:copy():merge(globalMgr.getGlobal('type', step.name))
197+
node:merge(globalMgr.getGlobal('type', step.name))
111198
elseif step.type == 'remove' then
112-
node = node:copyWithout(step.name)
199+
node:remove(step.name)
113200
elseif step.type == 'object' then
114201
node = callback(step.object, node) or node
115202
elseif step.type == 'save' then
116-
-- Nothing need to do
203+
-- nothing to do
117204
elseif step.type == 'load' then
118-
node = step.ref.node
205+
node = step.ref1.node
206+
elseif step.type == 'merge' then
207+
node:merge(step.ref1.node)
119208
end
120209
step.node = node
121210
end

0 commit comments

Comments
 (0)