@@ -6,7 +6,7 @@ local guide = require 'parser.guide'
66
77--- @class vm.runner
88--- @field _loc parser.object
9- --- @field _objs parser.object[]
9+ --- @field _casts parser.object[]
1010--- @field _callback vm.runner.callback
1111--- @field _mark table
1212--- @field _has table<parser.object , true>
@@ -51,34 +51,60 @@ function mt:_collect()
5151 for _ , ref in ipairs (self ._loc .ref ) do
5252 if ref .type == ' getlocal'
5353 or ref .type == ' setlocal' then
54- self . _objs [ # self . _objs + 1 ] = ref
55- if ref .start > finishPos then
56- finishPos = ref .start
54+ self : _markHas ( ref )
55+ if ref .finish > finishPos then
56+ finishPos = ref .finish
5757 end
5858 end
5959 end
6060
61- if # self ._objs == 0 then
62- return
63- end
64-
6561 local casts = self :_getCasts ()
6662 for _ , cast in ipairs (casts ) do
6763 if cast .loc [1 ] == self ._loc [1 ]
6864 and cast .start > startPos
6965 and cast .finish < finishPos
7066 and guide .getLocal (self ._loc , self ._loc [1 ], cast .start ) == self ._loc then
71- self ._objs [# self ._objs + 1 ] = cast
67+ self ._casts [# self ._casts + 1 ] = cast
68+ self :_markHas (cast )
7269 end
7370 end
71+ end
7472
75- table.sort (self ._objs , function (a , b )
76- return a .start < b .start
77- end )
78-
79- for _ , obj in ipairs (self ._objs ) do
80- self :_markHas (obj )
73+ --- @param pos integer
74+ --- @param topNode vm.node
75+ --- @return vm.node
76+ function mt :_fastWardCasts (pos , topNode )
77+ for i = self ._index , # self ._casts do
78+ local action = self ._casts [i ]
79+ if action .start > pos then
80+ self ._index = i
81+ return topNode
82+ end
83+ topNode = topNode :copy ()
84+ for _ , cast in ipairs (action .casts ) do
85+ if cast .mode == ' +' then
86+ if cast .optional then
87+ topNode :addOptional ()
88+ end
89+ if cast .extends then
90+ topNode :merge (vm .compileNode (cast .extends ))
91+ end
92+ elseif cast .mode == ' -' then
93+ if cast .optional then
94+ topNode :removeOptional ()
95+ end
96+ if cast .extends then
97+ topNode :removeNode (vm .compileNode (cast .extends ))
98+ end
99+ else
100+ if cast .extends then
101+ topNode :clear ()
102+ topNode :merge (vm .compileNode (cast .extends ))
103+ end
104+ end
105+ end
81106 end
107+ return topNode
82108end
83109
84110--- @param action parser.object
@@ -93,8 +119,13 @@ function mt:_lookIntoChild(action, topNode, outNode)
93119 end
94120 self ._mark [action ] = true
95121 if action .type == ' getlocal' then
96- self ._callback (action , topNode )
97- topNode = topNode :copy ():setTruthy ()
122+ if action .node == self ._loc then
123+ self ._callback (action , topNode )
124+ if outNode then
125+ topNode = topNode :copy ():setTruthy ()
126+ outNode = outNode :copy ():setFalsy ()
127+ end
128+ end
98129 elseif action .type == ' function' then
99130 self :_lookIntoBlock (action , topNode :copy ())
100131 elseif action .type == ' unary' then
@@ -110,8 +141,9 @@ function mt:_lookIntoChild(action, topNode, outNode)
110141 goto RETURN
111142 end
112143 if action .op .type == ' and' then
113- topNode = self :_lookIntoChild (action [1 ], topNode )
114- topNode = self :_lookIntoChild (action [2 ], topNode )
144+ local dummyNode = topNode :copy ()
145+ topNode = self :_lookIntoChild (action [1 ], topNode , dummyNode )
146+ topNode = self :_lookIntoChild (action [2 ], topNode , dummyNode )
115147 elseif action .op .type == ' or' then
116148 outNode = outNode or topNode :copy ()
117149 local topNode1 , outNode1 = self :_lookIntoChild (action [1 ], topNode , outNode )
@@ -133,7 +165,7 @@ function mt:_lookIntoChild(action, topNode, outNode)
133165 if handler .type == ' getlocal'
134166 and handler .node == self ._loc then
135167 -- if x == y then
136- self :_lookIntoChild (handler , topNode : copy () )
168+ topNode = self :_lookIntoChild (handler , topNode , outNode )
137169 local checkerNode = vm .compileNode (checker )
138170 if action .op .type == ' ==' then
139171 topNode = checkerNode
@@ -202,9 +234,12 @@ function mt:_lookIntoChild(action, topNode, outNode)
202234 or action .type == ' for' then
203235 topNode = self :_lookIntoBlock (action , topNode :copy ())
204236 elseif action .type == ' while' then
205- local blockNode , mainNode = self : _lookIntoChild ( action . filter , topNode : copy (), topNode : copy ())
237+ local blockNode , mainNode
206238 if action .filter then
207- self :_lookIntoChild (action .filter , topNode )
239+ blockNode , mainNode = self :_lookIntoChild (action .filter , topNode :copy (), topNode :copy ())
240+ else
241+ blockNode = topNode :copy ()
242+ mainNode = topNode :copy ()
208243 end
209244 blockNode = self :_lookIntoBlock (action , blockNode :copy ())
210245 if mainNode then
@@ -240,36 +275,34 @@ function mt:_lookIntoChild(action, topNode, outNode)
240275 topNode = mainNode
241276 elseif action .type == ' call' then
242277 if action .node .special == ' assert' and action .args and action .args [1 ] then
243- topNode = self :_lookIntoChild (action .args [1 ], topNode )
278+ topNode = self :_lookIntoChild (action .args [1 ], topNode , topNode : copy () )
244279 end
280+ elseif action .type == ' paren' then
281+ topNode , outNode = self :_lookIntoChild (action .exp , topNode , outNode )
245282 elseif action .type == ' setlocal' then
246283 if action .node == self ._loc then
247284 if action .value then
248285 self :_lookIntoChild (action .value , topNode )
249286 end
250287 topNode = self ._callback (action )
251288 end
252- elseif action .type == ' doc.cast' then
253- topNode = topNode :copy ()
254- for _ , cast in ipairs (action .casts ) do
255- if cast .mode == ' +' then
256- if cast .optional then
257- topNode :addOptional ()
258- end
259- if cast .extends then
260- topNode :merge (vm .compileNode (cast .extends ))
261- end
262- elseif cast .mode == ' -' then
263- if cast .optional then
264- topNode :removeOptional ()
265- end
266- if cast .extends then
267- topNode :removeNode (vm .compileNode (cast .extends ))
268- end
269- else
270- if cast .extends then
271- topNode :clear ()
272- topNode :merge (vm .compileNode (cast .extends ))
289+ elseif action .type == ' local' then
290+ if action .value
291+ and action .value .type == ' select' then
292+ local index = action .value .sindex
293+ local call = action .value .vararg
294+ if index == 1
295+ and call .type == ' call'
296+ and call .node
297+ and call .node .special == ' type'
298+ and call .args then
299+ local getLoc = call .args [1 ]
300+ if getLoc
301+ and getLoc .type == ' getlocal'
302+ and getLoc .node == self ._loc then
303+ for _ , ref in ipairs (action .ref ) do
304+ self :_markHas (ref )
305+ end
273306 end
274307 end
275308 end
@@ -292,9 +325,11 @@ function mt:_lookIntoBlock(block, topNode)
292325 end
293326 for _ , action in ipairs (block ) do
294327 if self ._has [action ] then
328+ topNode = self :_fastWardCasts (action .start , topNode )
295329 topNode = self :_lookIntoChild (action , topNode )
296330 end
297331 end
332+ topNode = self :_fastWardCasts (block .finish , topNode )
298333 return topNode
299334end
300335
@@ -307,7 +342,7 @@ function vm.launchRunner(loc, callback)
307342 end
308343 local self = setmetatable ({
309344 _loc = loc ,
310- _objs = {},
345+ _casts = {},
311346 _mark = {},
312347 _has = {},
313348 _main = main ,
@@ -316,8 +351,5 @@ function vm.launchRunner(loc, callback)
316351
317352 self :_collect ()
318353
319- if # self ._objs == 0 then
320- return
321- end
322354 self :_lookIntoBlock (main , vm .getNode (loc ):copy ())
323355end
0 commit comments