@@ -57,7 +57,7 @@ function mt:_collect()
5757 end
5858
5959 table.sort (self ._objs , function (a , b )
60- return ( a . range or a . start ) < ( b . range or b . start )
60+ return a . start < b . start
6161 end )
6262end
6363
6969function mt :_fastWard (pos , node )
7070 for i = self ._index , # self ._objs do
7171 local obj = self ._objs [i ]
72- if ( obj .range or obj . finish ) > pos then
72+ if obj .finish > pos then
7373 self ._index = i
7474 return node , obj
7575 end
7676 if obj .type == ' getlocal' then
7777 self ._callback (obj , node )
78- elseif obj .type == ' setlocal' then
79- local newNode = self ._callback (obj , node )
80- if newNode then
81- node = newNode :copy ()
82- end
8378 elseif obj .type == ' doc.cast' then
8479 node = node :copy ()
8580 for _ , cast in ipairs (obj .casts ) do
@@ -110,126 +105,64 @@ function mt:_fastWard(pos, node)
110105 return node , nil
111106end
112107
113- --- @param action parser.object
108+ --- @param exp parser.object
114109--- @param topNode vm.node
115110--- @param outNode ? vm.node
116111--- @return vm.node topNode
117112--- @return vm.node outNode
118- function mt :_lookInto ( action , topNode , outNode )
119- if not action then
113+ function mt :_lookIntoExp ( exp , topNode , outNode )
114+ if not exp then
120115 return topNode , outNode or topNode
121116 end
122- if self ._mark [action ] then
117+ if self ._mark [exp ] then
123118 return topNode , outNode or topNode
124119 end
125- self ._mark [action ] = true
120+ self ._mark [exp ] = true
126121 local top = self ._objs [self ._index ]
127122 if not top then
128123 return topNode , outNode or topNode
129124 end
130- if not guide .isInRange (action , top .finish )
131- -- trick for `local tp = type(x);if tp == 'string' then`
132- and action .type ~= ' binary' then
133- return topNode , outNode or topNode
134- end
135- local set
136- local value = vm .getObjectValue (action )
137- if value then
138- set = action
139- action = value
140- end
141- if action .type == ' function' then
142- self :_launchBlock (action , topNode :copy ())
143- elseif action .type == ' loop'
144- or action .type == ' in'
145- or action .type == ' repeat'
146- or action .type == ' for' then
147- topNode = self :_launchBlock (action , topNode :copy ())
148- elseif action .type == ' while' then
149- local blockNode , mainNode = self :_lookInto (action .filter , topNode :copy (), topNode :copy ())
150- if action .filter then
151- self :_fastWard (action .filter .finish , blockNode )
152- end
153- blockNode = self :_launchBlock (action , blockNode :copy ())
154- if mainNode then
155- topNode = mainNode :merge (blockNode )
156- end
157- elseif action .type == ' if' then
158- local hasElse
159- local mainNode = topNode :copy ()
160- local blockNodes = {}
161- for _ , subBlock in ipairs (action ) do
162- local blockNode = mainNode :copy ()
163- if subBlock .filter then
164- blockNode , mainNode = self :_lookInto (subBlock .filter , blockNode , mainNode )
165- self :_fastWard (subBlock .filter .finish , blockNode )
166- else
167- hasElse = true
168- mainNode :clear ()
169- end
170- blockNode = self :_launchBlock (subBlock , blockNode :copy ())
171- local neverReturn = subBlock .hasReturn
172- or subBlock .hasGoTo
173- or subBlock .hasBreak
174- or subBlock .hasError
175- if not neverReturn then
176- blockNodes [# blockNodes + 1 ] = blockNode
177- end
178- end
179- if not hasElse and not topNode :hasKnownType () then
180- mainNode :merge (vm .declareGlobal (' type' , ' unknown' ))
181- end
182- for _ , blockNode in ipairs (blockNodes ) do
183- mainNode :merge (blockNode )
184- end
185- topNode = mainNode
186- elseif action .type == ' getlocal' then
187- if action .node == self ._loc then
188- topNode = self :_fastWard (action .finish , topNode )
189- topNode = topNode :copy ():setTruthy ()
190- if outNode then
191- outNode :setFalsy ()
192- end
193- end
194- elseif action .type == ' unary' then
195- if not action [1 ] then
125+ if exp .type == ' function' then
126+ self :_launchBlock (exp , topNode :copy ())
127+ elseif exp .type == ' unary' then
128+ if not exp [1 ] then
196129 goto RETURN
197130 end
198- if action .op .type == ' not' then
131+ if exp .op .type == ' not' then
199132 outNode = outNode or topNode :copy ()
200- outNode , topNode = self :_lookInto ( action [1 ], topNode , outNode )
133+ outNode , topNode = self :_lookIntoExp ( exp [1 ], topNode , outNode )
201134 end
202- elseif action .type == ' binary' then
203- if not action [1 ] or not action [2 ] then
135+ elseif exp .type == ' binary' then
136+ if not exp [1 ] or not exp [2 ] then
204137 goto RETURN
205138 end
206- if action .op .type == ' and' then
207- topNode = self :_lookInto ( action [1 ], topNode )
208- topNode = self :_lookInto ( action [2 ], topNode )
209- elseif action .op .type == ' or' then
139+ if exp .op .type == ' and' then
140+ topNode = self :_lookIntoExp ( exp [1 ], topNode )
141+ topNode = self :_lookIntoExp ( exp [2 ], topNode )
142+ elseif exp .op .type == ' or' then
210143 outNode = outNode or topNode :copy ()
211- local topNode1 , outNode1 = self :_lookInto ( action [1 ], topNode , outNode )
212- local topNode2 , outNode2 = self :_lookInto ( action [2 ], outNode1 , outNode1 :copy ())
144+ local topNode1 , outNode1 = self :_lookIntoExp ( exp [1 ], topNode , outNode )
145+ local topNode2 , outNode2 = self :_lookIntoExp ( exp [2 ], outNode1 , outNode1 :copy ())
213146 topNode = vm .createNode (topNode1 , topNode2 )
214147 outNode = outNode2 :copy ()
215- elseif action .op .type == ' =='
216- or action .op .type == ' ~=' then
217- local exp , checker
148+ elseif exp .op .type == ' =='
149+ or exp .op .type == ' ~=' then
150+ local handler , checker
218151 for i = 1 , 2 do
219- if guide .isLiteral (action [i ]) then
220- checker = action [i ]
221- exp = action [3 - i ] -- Copilot tells me use `3-i` instead of `i%2+1`
152+ if guide .isLiteral (exp [i ]) then
153+ checker = exp [i ]
154+ handler = exp [3 - i ] -- Copilot tells me use `3-i` instead of `i%2+1`
222155 end
223156 end
224- if not exp then
157+ if not handler then
225158 goto RETURN
226159 end
227- if exp .type == ' getlocal'
228- and exp .node == self ._loc then
160+ if handler .type == ' getlocal'
161+ and handler .node == self ._loc then
229162 -- if x == y then
230163 self :_fastWard (exp .finish , topNode :copy ())
231164 local checkerNode = vm .compileNode (checker )
232- if action .op .type == ' ==' then
165+ if exp .op .type == ' ==' then
233166 topNode = checkerNode
234167 if outNode then
235168 outNode :removeNode (topNode )
@@ -240,16 +173,16 @@ function mt:_lookInto(action, topNode, outNode)
240173 outNode = checkerNode
241174 end
242175 end
243- elseif exp .type == ' call'
176+ elseif handler .type == ' call'
244177 and checker .type == ' string'
245- and exp .node .special == ' type'
246- and exp .args
247- and exp .args [1 ]
248- and exp .args [1 ].type == ' getlocal'
249- and exp .args [1 ].node == self ._loc then
178+ and handler .node .special == ' type'
179+ and handler .args
180+ and handler .args [1 ]
181+ and handler .args [1 ].type == ' getlocal'
182+ and handler .args [1 ].node == self ._loc then
250183 -- if type(x) == 'string' then
251184 self :_fastWard (exp .finish , topNode :copy ())
252- if action .op .type == ' ==' then
185+ if exp .op .type == ' ==' then
253186 topNode :narrow (checker [1 ])
254187 if outNode then
255188 outNode :remove (checker [1 ])
@@ -260,9 +193,9 @@ function mt:_lookInto(action, topNode, outNode)
260193 outNode :narrow (checker [1 ])
261194 end
262195 end
263- elseif exp .type == ' getlocal'
196+ elseif handler .type == ' getlocal'
264197 and checker .type == ' string' then
265- local nodeValue = vm .getObjectValue (exp .node )
198+ local nodeValue = vm .getObjectValue (handler .node )
266199 if nodeValue
267200 and nodeValue .type == ' select'
268201 and nodeValue .sindex == 1 then
@@ -275,7 +208,7 @@ function mt:_lookInto(action, topNode, outNode)
275208 and call .args [1 ].type == ' getlocal'
276209 and call .args [1 ].node == self ._loc then
277210 -- `local tp = type(x);if tp == 'string' then`
278- if action .op .type == ' ==' then
211+ if exp .op .type == ' ==' then
279212 topNode :narrow (checker [1 ])
280213 if outNode then
281214 outNode :remove (checker [1 ])
@@ -290,33 +223,117 @@ function mt:_lookInto(action, topNode, outNode)
290223 end
291224 end
292225 end
226+ elseif exp .type == ' getlocal' then
227+ if exp .node == self ._loc then
228+ topNode = self :_fastWard (exp .finish , topNode )
229+ topNode = topNode :copy ():setTruthy ()
230+ if outNode then
231+ outNode :setFalsy ()
232+ end
233+ end
234+ elseif exp .type == ' paren' then
235+ topNode , outNode = self :_lookIntoExp (exp .exp , topNode , outNode )
236+ elseif exp .type == ' getindex' then
237+ self :_lookIntoExp (exp .index , topNode )
238+ elseif exp .type == ' table' then
239+ for _ , field in ipairs (exp ) do
240+ self :_lookIntoAction (field , topNode )
241+ end
242+ end
243+ :: RETURN::
244+ topNode = self :_fastWard (exp .finish , topNode )
245+ return topNode , outNode or topNode
246+ end
247+
248+ --- @param action parser.object
249+ --- @param topNode vm.node
250+ --- @return vm.node topNode
251+ function mt :_lookIntoAction (action , topNode )
252+ if not action then
253+ return topNode
254+ end
255+ if self ._mark [action ] then
256+ return topNode
257+ end
258+ self ._mark [action ] = true
259+ local top = self ._objs [self ._index ]
260+ if not top then
261+ return topNode
262+ end
263+ if not guide .isInRange (action , top .finish )
264+ -- trick for `local tp = type(x);if tp == 'string' then`
265+ and action .type ~= ' binary' then
266+ return topNode
267+ end
268+ local value = vm .getObjectValue (action )
269+ if value then
270+ self :_lookIntoExp (value , topNode :copy ())
271+ end
272+ if action .type == ' setlocal' then
273+ local newTopNode = self ._callback (action , topNode )
274+ if newTopNode then
275+ topNode = newTopNode
276+ end
277+ elseif action .type == ' function' then
278+ self :_launchBlock (action , topNode :copy ())
279+ elseif action .type == ' loop'
280+ or action .type == ' in'
281+ or action .type == ' repeat'
282+ or action .type == ' for' then
283+ topNode = self :_launchBlock (action , topNode :copy ())
284+ elseif action .type == ' while' then
285+ local blockNode , mainNode = self :_lookIntoExp (action .filter , topNode :copy (), topNode :copy ())
286+ if action .filter then
287+ self :_fastWard (action .filter .finish , blockNode )
288+ end
289+ blockNode = self :_launchBlock (action , blockNode :copy ())
290+ if mainNode then
291+ topNode = mainNode :merge (blockNode )
292+ end
293+ elseif action .type == ' if' then
294+ local hasElse
295+ local mainNode = topNode :copy ()
296+ local blockNodes = {}
297+ for _ , subBlock in ipairs (action ) do
298+ local blockNode = mainNode :copy ()
299+ if subBlock .filter then
300+ blockNode , mainNode = self :_lookIntoExp (subBlock .filter , blockNode , mainNode )
301+ self :_fastWard (subBlock .filter .finish , blockNode )
302+ else
303+ hasElse = true
304+ mainNode :clear ()
305+ end
306+ blockNode = self :_launchBlock (subBlock , blockNode :copy ())
307+ local neverReturn = subBlock .hasReturn
308+ or subBlock .hasGoTo
309+ or subBlock .hasBreak
310+ or subBlock .hasError
311+ if not neverReturn then
312+ blockNodes [# blockNodes + 1 ] = blockNode
313+ end
314+ end
315+ if not hasElse and not topNode :hasKnownType () then
316+ mainNode :merge (vm .declareGlobal (' type' , ' unknown' ))
317+ end
318+ for _ , blockNode in ipairs (blockNodes ) do
319+ mainNode :merge (blockNode )
320+ end
321+ topNode = mainNode
293322 elseif action .type == ' call' then
294323 if action .node .special == ' assert' and action .args and action .args [1 ] then
295- topNode = self :_lookInto (action .args [1 ], topNode )
324+ topNode = self :_lookIntoExp (action .args [1 ], topNode )
296325 elseif action .args then
297326 for _ , arg in ipairs (action .args ) do
298- self :_lookInto (arg , topNode )
327+ self :_lookIntoExp (arg , topNode )
299328 end
300329 end
301- elseif action .type == ' paren' then
302- topNode , outNode = self :_lookInto (action .exp , topNode , outNode )
303330 elseif action .type == ' return' then
304331 for _ , rtn in ipairs (action ) do
305- self :_lookInto (rtn , topNode )
306- end
307- elseif action .type == ' getindex' then
308- self :_lookInto (action .index , topNode )
309- elseif action .type == ' table' then
310- for _ , field in ipairs (action ) do
311- self :_lookInto (field , topNode )
332+ self :_lookIntoExp (rtn , topNode )
312333 end
313334 end
314- :: RETURN::
315335 topNode = self :_fastWard (action .finish , topNode )
316- if set then
317- topNode = self :_fastWard (set .range or set .finish , topNode )
318- end
319- return topNode , outNode or topNode
336+ return topNode
320337end
321338
322339--- @param block parser.object
@@ -328,18 +345,17 @@ function mt:_launchBlock(block, node)
328345 return topNode
329346 end
330347 for _ , action in ipairs (block ) do
331- if (action .range or action .finish ) < ( top .range or top . finish ) then
348+ if (action .range or action .finish ) < top .finish then
332349 goto CONTINUE
333350 end
334- topNode = self :_lookInto (action , topNode )
335- topNode , top = self :_fastWard (action .range or action . finish , topNode )
351+ topNode = self :_lookIntoAction (action , topNode )
352+ topNode , top = self :_fastWard (action .finish , topNode )
336353 if not top then
337354 return topNode
338355 end
339356 :: CONTINUE::
340357 end
341- -- `x = function () end`: don't touch `x` in the end of function
342- topNode = self :_fastWard (block .finish - 1 , topNode )
358+ topNode = self :_fastWard (block .finish , topNode )
343359 return topNode
344360end
345361
0 commit comments